mirror of
https://github.com/PeernetOfficial/core.git
synced 2026-07-17 02:47:51 +01:00
Major refactoring of the code base into Backend structure. Increase version number to Alpha 6 to prepare for the upcoming release.
This commit is contained in:
@@ -24,35 +24,35 @@ type BlockchainCache struct {
|
||||
|
||||
store *blockchain.MultiStore
|
||||
peerLock *locker.Locker
|
||||
|
||||
backend *Backend
|
||||
}
|
||||
|
||||
func initBlockchainCache(BlockchainDirectory string, MaxBlockSize, MaxBlockCount, LimitTotalRecords uint64) (cache *BlockchainCache) {
|
||||
if BlockchainDirectory == "" {
|
||||
return nil
|
||||
func (backend *Backend) initBlockchainCache() {
|
||||
if backend.Config.BlockchainGlobal == "" {
|
||||
return
|
||||
}
|
||||
|
||||
backend.GlobalBlockchainCache = &BlockchainCache{
|
||||
backend: backend,
|
||||
BlockchainDirectory: backend.Config.BlockchainGlobal,
|
||||
MaxBlockSize: backend.Config.CacheMaxBlockSize,
|
||||
MaxBlockCount: backend.Config.CacheMaxBlockCount,
|
||||
LimitTotalRecords: backend.Config.LimitTotalRecords,
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
cache = &BlockchainCache{
|
||||
BlockchainDirectory: BlockchainDirectory,
|
||||
MaxBlockSize: MaxBlockSize,
|
||||
MaxBlockCount: MaxBlockCount,
|
||||
LimitTotalRecords: LimitTotalRecords,
|
||||
}
|
||||
|
||||
cache.store, err = blockchain.InitMultiStore(BlockchainDirectory)
|
||||
backend.GlobalBlockchainCache.store, err = blockchain.InitMultiStore(backend.Config.BlockchainGlobal)
|
||||
if err != nil {
|
||||
Filters.LogError("initBlockchainCache", "initializing database '%s': %s", BlockchainDirectory, err.Error())
|
||||
return nil
|
||||
backend.Filters.LogError("initBlockchainCache", "initializing database '%s': %s", backend.Config.BlockchainGlobal, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cache.peerLock = locker.Initialize()
|
||||
backend.GlobalBlockchainCache.peerLock = locker.Initialize()
|
||||
|
||||
if LimitTotalRecords > 0 && cache.store.Database.Count() >= LimitTotalRecords {
|
||||
cache.ReadOnly = true
|
||||
if backend.Config.LimitTotalRecords > 0 && backend.GlobalBlockchainCache.store.Database.Count() >= backend.Config.LimitTotalRecords {
|
||||
backend.GlobalBlockchainCache.ReadOnly = true
|
||||
}
|
||||
|
||||
return cache
|
||||
}
|
||||
|
||||
// SeenBlockchainVersion shall be called with information about another peer's blockchain.
|
||||
@@ -76,7 +76,7 @@ func (cache *BlockchainCache) SeenBlockchainVersion(peer *PeerInfo) {
|
||||
cache.store.WriteBlock(peer.PublicKey, peer.BlockchainVersion, targetBlock.Offset, data)
|
||||
header.ListBlocks = append(header.ListBlocks, targetBlock.Offset)
|
||||
|
||||
currentBackend.SearchIndex.IndexNewBlock(peer.PublicKey, peer.BlockchainVersion, targetBlock.Offset, data)
|
||||
cache.backend.SearchIndex.IndexNewBlock(peer.PublicKey, peer.BlockchainVersion, targetBlock.Offset, data)
|
||||
})
|
||||
|
||||
// only update the blockchain header if it changed
|
||||
@@ -98,7 +98,7 @@ func (cache *BlockchainCache) SeenBlockchainVersion(peer *PeerInfo) {
|
||||
case blockchain.MultiStatusInvalidRemote:
|
||||
cache.store.DeleteBlockchain(peer.PublicKey, header)
|
||||
|
||||
currentBackend.SearchIndex.UnindexBlockchain(peer.PublicKey)
|
||||
cache.backend.SearchIndex.UnindexBlockchain(peer.PublicKey)
|
||||
|
||||
case blockchain.MultiStatusHeaderNA:
|
||||
if header, err = cache.store.NewBlockchainHeader(peer.PublicKey, peer.BlockchainVersion, peer.BlockchainHeight); err != nil {
|
||||
@@ -111,7 +111,7 @@ func (cache *BlockchainCache) SeenBlockchainVersion(peer *PeerInfo) {
|
||||
// delete existing data first, then create it new
|
||||
cache.store.DeleteBlockchain(peer.PublicKey, header)
|
||||
|
||||
currentBackend.SearchIndex.UnindexBlockchain(peer.PublicKey)
|
||||
cache.backend.SearchIndex.UnindexBlockchain(peer.PublicKey)
|
||||
|
||||
if header, err = cache.store.NewBlockchainHeader(peer.PublicKey, peer.BlockchainVersion, peer.BlockchainHeight); err != nil {
|
||||
return
|
||||
@@ -138,12 +138,12 @@ func (cache *BlockchainCache) SeenBlockchainVersion(peer *PeerInfo) {
|
||||
// It will use the blockchain version and height to update the data lake as appropriate.
|
||||
// This function is called in the Go routine of the packet worker and therefore must not stall.
|
||||
func (peer *PeerInfo) remoteBlockchainUpdate() {
|
||||
if currentBackend.GlobalBlockchainCache == nil || currentBackend.GlobalBlockchainCache.ReadOnly || peer.BlockchainVersion == 0 && peer.BlockchainHeight == 0 {
|
||||
if peer.Backend.GlobalBlockchainCache == nil || peer.Backend.GlobalBlockchainCache.ReadOnly || peer.BlockchainVersion == 0 && peer.BlockchainHeight == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: This entire function should be instead a non-blocking message via a buffer channel.
|
||||
go currentBackend.GlobalBlockchainCache.SeenBlockchainVersion(peer)
|
||||
go peer.Backend.GlobalBlockchainCache.SeenBlockchainVersion(peer)
|
||||
}
|
||||
|
||||
func (cache *BlockchainCache) ReadFile(PublicKey *btcec.PublicKey, Version, BlockNumber uint64, FileID uuid.UUID) (file blockchain.BlockRecordFile, raw []byte, found bool, err error) {
|
||||
@@ -164,14 +164,14 @@ func (cache *BlockchainCache) ReadFile(PublicKey *btcec.PublicKey, Version, Bloc
|
||||
// ReadBlock reads a block and decodes the records.
|
||||
func (cache *BlockchainCache) ReadBlock(PublicKey *btcec.PublicKey, Version, BlockNumber uint64) (decoded *blockchain.BlockDecoded, raw []byte, found bool, err error) {
|
||||
// requesting a block from the user's blockchain?
|
||||
if PublicKey.IsEqual(peerPublicKey) {
|
||||
_, _, version := UserBlockchain.Header()
|
||||
if PublicKey.IsEqual(cache.backend.peerPublicKey) {
|
||||
_, _, version := cache.backend.UserBlockchain.Header()
|
||||
if Version != version {
|
||||
return nil, nil, false, nil
|
||||
}
|
||||
|
||||
var status int
|
||||
raw, status, err = UserBlockchain.GetBlockRaw(BlockNumber)
|
||||
raw, status, err = cache.backend.UserBlockchain.GetBlockRaw(BlockNumber)
|
||||
if err != nil || status != blockchain.StatusOK {
|
||||
return nil, raw, false, err
|
||||
}
|
||||
|
||||
@@ -12,28 +12,25 @@ import (
|
||||
"github.com/PeernetOfficial/core/blockchain"
|
||||
)
|
||||
|
||||
// UserBlockchain is the user's blockchain and exports functions to directly read and write it
|
||||
var UserBlockchain *blockchain.Blockchain
|
||||
|
||||
// initUserBlockchain initializes the users blockchain. It creates the blockchain file if it does not exist already.
|
||||
// If it is corrupted, it will log the error and exit the process.
|
||||
func initUserBlockchain() {
|
||||
func (backend *Backend) initUserBlockchain() {
|
||||
var err error
|
||||
UserBlockchain, err = blockchain.Init(peerPrivateKey, config.BlockchainMain)
|
||||
backend.UserBlockchain, err = blockchain.Init(backend.peerPrivateKey, backend.Config.BlockchainMain)
|
||||
|
||||
if err != nil {
|
||||
Filters.LogError("initUserBlockchain", "error: %s\n", err.Error())
|
||||
backend.Filters.LogError("initUserBlockchain", "error: %s\n", err.Error())
|
||||
os.Exit(ExitBlockchainCorrupt)
|
||||
}
|
||||
}
|
||||
|
||||
// Index the user's blockchain each time there is an update.
|
||||
func (backend *Backend) userBlockchainUpdateSearchIndex() {
|
||||
UserBlockchain.BlockchainUpdate = func(blockchainU *blockchain.Blockchain, oldHeight, oldVersion, newHeight, newVersion uint64) {
|
||||
backend.UserBlockchain.BlockchainUpdate = func(blockchainU *blockchain.Blockchain, oldHeight, oldVersion, newHeight, newVersion uint64) {
|
||||
|
||||
if newVersion != oldVersion || newHeight < oldHeight {
|
||||
// invalidate search index data for the user's blockchain
|
||||
backend.SearchIndex.UnindexBlockchain(peerPublicKey)
|
||||
backend.SearchIndex.UnindexBlockchain(backend.peerPublicKey)
|
||||
|
||||
// reindex everything
|
||||
for blockN := uint64(0); blockN < newHeight; blockN++ {
|
||||
@@ -42,7 +39,7 @@ func (backend *Backend) userBlockchainUpdateSearchIndex() {
|
||||
continue
|
||||
}
|
||||
|
||||
backend.SearchIndex.IndexNewBlock(peerPublicKey, newVersion, blockN, raw)
|
||||
backend.SearchIndex.IndexNewBlock(backend.peerPublicKey, newVersion, blockN, raw)
|
||||
}
|
||||
|
||||
return
|
||||
@@ -56,7 +53,7 @@ func (backend *Backend) userBlockchainUpdateSearchIndex() {
|
||||
continue
|
||||
}
|
||||
|
||||
backend.SearchIndex.IndexNewBlock(peerPublicKey, newVersion, blockN, raw)
|
||||
backend.SearchIndex.IndexNewBlock(backend.peerPublicKey, newVersion, blockN, raw)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
53
Bootstrap.go
53
Bootstrap.go
@@ -29,33 +29,34 @@ type rootPeer struct {
|
||||
peer *PeerInfo // loaded PeerInfo
|
||||
publicKey *btcec.PublicKey // Public key
|
||||
addresses []*net.UDPAddr // IP:Port addresses
|
||||
backend *Backend
|
||||
}
|
||||
|
||||
var rootPeers map[[btcec.PubKeyBytesLenCompressed]byte]*rootPeer
|
||||
|
||||
// initSeedList loads the seed list from the config
|
||||
// Note: This should be called before any network listening function so that incoming root peers are properly recognized.
|
||||
func initSeedList() {
|
||||
func (backend *Backend) initSeedList() {
|
||||
rootPeers = make(map[[btcec.PubKeyBytesLenCompressed]byte]*rootPeer)
|
||||
recentContacts = make(map[[btcec.PubKeyBytesLenCompressed]byte]*recentContactInfo)
|
||||
|
||||
loopSeedList:
|
||||
for _, seed := range config.SeedList {
|
||||
peer := &rootPeer{}
|
||||
for _, seed := range backend.Config.SeedList {
|
||||
peer := &rootPeer{backend: backend}
|
||||
|
||||
// parse the Public Key
|
||||
publicKeyB, err := hex.DecodeString(seed.PublicKey)
|
||||
if err != nil {
|
||||
Filters.LogError("initSeedList", "public key '%s': %v\n", seed.PublicKey, err.Error())
|
||||
backend.Filters.LogError("initSeedList", "public key '%s': %v\n", seed.PublicKey, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
if peer.publicKey, err = btcec.ParsePubKey(publicKeyB, btcec.S256()); err != nil {
|
||||
Filters.LogError("initSeedList", "public key '%s': %v\n", seed.PublicKey, err.Error())
|
||||
backend.Filters.LogError("initSeedList", "public key '%s': %v\n", seed.PublicKey, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
if peer.publicKey.IsEqual(peerPublicKey) { // skip if self
|
||||
if peer.publicKey.IsEqual(backend.peerPublicKey) { // skip if self
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -63,7 +64,7 @@ loopSeedList:
|
||||
for _, addressA := range seed.Address {
|
||||
address, err := parseAddress(addressA)
|
||||
if err != nil {
|
||||
Filters.LogError("initSeedList", "public key '%s' address '%s': %v\n", seed.PublicKey, addressA, err.Error())
|
||||
backend.Filters.LogError("initSeedList", "public key '%s' address '%s': %v\n", seed.PublicKey, addressA, err.Error())
|
||||
continue loopSeedList
|
||||
}
|
||||
|
||||
@@ -99,22 +100,22 @@ func parseAddress(Address string) (remote *net.UDPAddr, err error) {
|
||||
// contact tries to contact the root peer on all networks
|
||||
func (peer *rootPeer) contact() {
|
||||
// If already in peer list, no need to contact.
|
||||
if PeerlistLookup(peer.publicKey) != nil {
|
||||
if peer.backend.PeerlistLookup(peer.publicKey) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, address := range peer.addresses {
|
||||
// Port internal is always set to 0 for root peers. It disables NAT detection and will not send out a Traverse message.
|
||||
contactArbitraryPeer(peer.publicKey, address, 0, false)
|
||||
peer.backend.contactArbitraryPeer(peer.publicKey, address, 0, false)
|
||||
}
|
||||
}
|
||||
|
||||
// bootstrap connects to the initial set of peers.
|
||||
func bootstrap() {
|
||||
func (backend *Backend) bootstrap() {
|
||||
go resetRecentContacts()
|
||||
|
||||
if len(rootPeers) == 0 {
|
||||
Filters.LogError("bootstrap", "warning: Empty list of root peers. Connectivity relies on local peer discovery and incoming connections.\n")
|
||||
backend.Filters.LogError("bootstrap", "warning: Empty list of root peers. Connectivity relies on local peer discovery and incoming connections.\n")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -130,7 +131,7 @@ func bootstrap() {
|
||||
for _, peer := range rootPeers {
|
||||
if peer.peer != nil {
|
||||
connectedCount++
|
||||
} else if peer.peer = PeerlistLookup(peer.publicKey); peer.peer != nil {
|
||||
} else if peer.peer = peer.backend.PeerlistLookup(peer.publicKey); peer.peer != nil {
|
||||
connectedCount++
|
||||
}
|
||||
}
|
||||
@@ -162,7 +163,7 @@ func bootstrap() {
|
||||
}
|
||||
}
|
||||
|
||||
Filters.LogError("bootstrap", "unable to connect to at least 2 root peers, aborting\n")
|
||||
backend.Filters.LogError("bootstrap", "unable to connect to at least 2 root peers, aborting\n")
|
||||
}
|
||||
|
||||
func (nets *Networks) autoMulticastBroadcast() {
|
||||
@@ -172,13 +173,13 @@ func (nets *Networks) autoMulticastBroadcast() {
|
||||
|
||||
for _, network := range nets.networks6 {
|
||||
if err := network.MulticastIPv6Send(); err != nil {
|
||||
Filters.LogError("autoMulticastBroadcast", "multicast from network address '%s': %v\n", network.address.IP.String(), err.Error())
|
||||
nets.backend.Filters.LogError("autoMulticastBroadcast", "multicast from network address '%s': %v\n", network.address.IP.String(), err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
for _, network := range nets.networks4 {
|
||||
if err := network.BroadcastIPv4Send(); err != nil {
|
||||
Filters.LogError("autoMulticastBroadcast", "broadcast from network address '%s': %v\n", network.address.IP.String(), err.Error())
|
||||
nets.backend.Filters.LogError("autoMulticastBroadcast", "broadcast from network address '%s': %v\n", network.address.IP.String(), err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,7 +191,7 @@ func (nets *Networks) autoMulticastBroadcast() {
|
||||
for {
|
||||
time.Sleep(time.Second * 10)
|
||||
|
||||
if PeerlistCount() >= 1 {
|
||||
if nets.backend.PeerlistCount() >= 1 {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -205,18 +206,18 @@ func (nets *Networks) autoMulticastBroadcast() {
|
||||
}
|
||||
|
||||
// contactArbitraryPeer contacts a new arbitrary peer for the first time.
|
||||
func contactArbitraryPeer(publicKey *btcec.PublicKey, address *net.UDPAddr, receiverPortInternal uint16, receiverFirewall bool) (contacted bool) {
|
||||
func (backend *Backend) contactArbitraryPeer(publicKey *btcec.PublicKey, address *net.UDPAddr, receiverPortInternal uint16, receiverFirewall bool) (contacted bool) {
|
||||
findSelf := ShouldSendFindSelf()
|
||||
_, blockchainHeight, blockchainVersion := UserBlockchain.Header()
|
||||
packets := protocol.EncodeAnnouncement(true, findSelf, nil, nil, nil, FeatureSupport(), blockchainHeight, blockchainVersion, userAgent)
|
||||
_, blockchainHeight, blockchainVersion := backend.UserBlockchain.Header()
|
||||
packets := protocol.EncodeAnnouncement(true, findSelf, nil, nil, nil, backend.FeatureSupport(), blockchainHeight, blockchainVersion, backend.userAgent)
|
||||
if len(packets) == 0 {
|
||||
return false
|
||||
}
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandAnnouncement, Payload: packets[0]}
|
||||
|
||||
Filters.MessageOutAnnouncement(publicKey, nil, raw, findSelf, nil, nil, nil)
|
||||
backend.Filters.MessageOutAnnouncement(publicKey, nil, raw, findSelf, nil, nil, nil)
|
||||
|
||||
networks.sendAllNetworks(publicKey, raw, address, receiverPortInternal, receiverFirewall, nil, &bootstrapFindSelf{})
|
||||
backend.networks.sendAllNetworks(publicKey, raw, address, receiverPortInternal, receiverFirewall, nil, &bootstrapFindSelf{})
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -236,12 +237,12 @@ func (peer *PeerInfo) cmdResponseBootstrapFindSelf(msg *protocol.MessageResponse
|
||||
}
|
||||
|
||||
for _, closePeer := range closest {
|
||||
if isReturnedPeerBadQuality(&closePeer) {
|
||||
if peer.Backend.isReturnedPeerBadQuality(&closePeer) {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the peer is already in the peer list, no need to contact it again.
|
||||
if PeerlistLookup(closePeer.PublicKey) != nil {
|
||||
if peer.Backend.PeerlistLookup(closePeer.PublicKey) != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -258,7 +259,7 @@ func (peer *PeerInfo) cmdResponseBootstrapFindSelf(msg *protocol.MessageResponse
|
||||
}
|
||||
|
||||
// Initiate contact. Once a response comes back, the peer will be actually added to the peer list.
|
||||
contactArbitraryPeer(closePeer.PublicKey, &net.UDPAddr{IP: address.IP, Port: int(address.Port)}, address.PortInternal, closePeer.Features&(1<<protocol.FeatureFirewall) > 0)
|
||||
peer.Backend.contactArbitraryPeer(closePeer.PublicKey, &net.UDPAddr{IP: address.IP, Port: int(address.Port)}, address.PortInternal, closePeer.Features&(1<<protocol.FeatureFirewall) > 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,7 +271,7 @@ func ShouldSendFindSelf() bool {
|
||||
}
|
||||
|
||||
// isReturnedPeerBadQuality checks if the returned peer record is bad quality and should be discarded
|
||||
func isReturnedPeerBadQuality(record *protocol.PeerRecord) bool {
|
||||
func (backend *Backend) isReturnedPeerBadQuality(record *protocol.PeerRecord) bool {
|
||||
isIPv4 := record.IPv4 != nil && !record.IPv4.IsUnspecified()
|
||||
isIPv6 := record.IPv6 != nil && !record.IPv6.IsUnspecified()
|
||||
|
||||
@@ -286,7 +287,7 @@ func isReturnedPeerBadQuality(record *protocol.PeerRecord) bool {
|
||||
}
|
||||
|
||||
// Must not be self. There is no point that a remote peer would return self
|
||||
if record.PublicKey.IsEqual(peerPublicKey) {
|
||||
if record.PublicKey.IsEqual(backend.peerPublicKey) {
|
||||
//fmt.Printf("IsReturnedPeerBadQuality received self peer\n")
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func (peer *PeerInfo) cmdTraverseForward(msg *protocol.MessageTraverse) {
|
||||
// Check if the target peer is known in the peer list. If not, nothing will be done.
|
||||
// The original sender should only send the Traverse message as answer to a Response that contains a reported peer that is behind a NAT.
|
||||
// In that case the target peer should be still in this peers' peer list.
|
||||
peerTarget := PeerlistLookup(msg.TargetPeer)
|
||||
peerTarget := peer.Backend.PeerlistLookup(msg.TargetPeer)
|
||||
if peerTarget == nil {
|
||||
return
|
||||
}
|
||||
@@ -72,7 +72,7 @@ func (peer *PeerInfo) cmdTraverseReceive(msg *protocol.MessageTraverse) {
|
||||
|
||||
// Already an active connection established? The relayed message should not be needed in this case.
|
||||
// This could be changed in the future if it turns out that there are 1-way connection issues.
|
||||
if peerTarget := PeerlistLookup(msg.SignerPublicKey); peerTarget != nil {
|
||||
if peerTarget := peer.Backend.PeerlistLookup(msg.SignerPublicKey); peerTarget != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -99,13 +99,13 @@ func (peer *PeerInfo) cmdTraverseReceive(msg *protocol.MessageTraverse) {
|
||||
|
||||
// ---- fork packetWorker to decode and validate embedded packet ---
|
||||
// Due to missing connection and other embedded details in the message (such as ports), the packet is not just simply queued to rawPacketsIncoming.
|
||||
decoded, senderPublicKey, err := protocol.PacketDecrypt(msg.EmbeddedPacketRaw, peerPublicKey)
|
||||
decoded, senderPublicKey, err := protocol.PacketDecrypt(msg.EmbeddedPacketRaw, peer.Backend.peerPublicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !senderPublicKey.IsEqual(msg.SignerPublicKey) {
|
||||
return
|
||||
} else if senderPublicKey.IsEqual(peerPublicKey) {
|
||||
} else if senderPublicKey.IsEqual(peer.Backend.peerPublicKey) {
|
||||
return
|
||||
} else if decoded.Protocol != 0 {
|
||||
return
|
||||
@@ -115,7 +115,7 @@ func (peer *PeerInfo) cmdTraverseReceive(msg *protocol.MessageTraverse) {
|
||||
|
||||
// process the packet and create a virtual peer
|
||||
raw := &protocol.MessageRaw{SenderPublicKey: senderPublicKey, PacketRaw: *decoded}
|
||||
peerV := &PeerInfo{PublicKey: senderPublicKey, connectionActive: nil, connectionLatest: nil, NodeID: protocol.PublicKey2NodeID(senderPublicKey), messageSequence: rand.Uint32(), isVirtual: true, targetAddresses: addresses}
|
||||
peerV := &PeerInfo{Backend: peer.Backend, PublicKey: senderPublicKey, connectionActive: nil, connectionLatest: nil, NodeID: protocol.PublicKey2NodeID(senderPublicKey), messageSequence: rand.Uint32(), isVirtual: true, targetAddresses: addresses}
|
||||
|
||||
// process it!
|
||||
switch decoded.Command {
|
||||
|
||||
36
Commands.go
36
Commands.go
@@ -38,12 +38,12 @@ func (peer *PeerInfo) cmdAnouncement(msg *protocol.MessageAnnouncement, connecti
|
||||
|
||||
// FIND_SELF: Requesting peers close to the sender?
|
||||
if msg.Actions&(1<<protocol.ActionFindSelf) > 0 {
|
||||
Filters.IncomingRequest(peer, protocol.ActionFindSelf, peer.NodeID, nil)
|
||||
peer.Backend.Filters.IncomingRequest(peer, protocol.ActionFindSelf, peer.NodeID, nil)
|
||||
|
||||
selfD := protocol.Hash2Peer{ID: protocol.KeyHash{Hash: peer.NodeID}}
|
||||
|
||||
// do not respond the caller's own peer (add to ignore list)
|
||||
for _, node := range nodesDHT.GetClosestContacts(respondClosesContactsCount, peer.NodeID, filterFunc(connection.IsLocal(), allowIPv4, allowIPv6), peer.NodeID) {
|
||||
for _, node := range peer.Backend.nodesDHT.GetClosestContacts(respondClosesContactsCount, peer.NodeID, filterFunc(connection.IsLocal(), allowIPv4, allowIPv6), peer.NodeID) {
|
||||
if info := node.Info.(*PeerInfo).peer2Record(connection.IsLocal(), allowIPv4, allowIPv6); info != nil {
|
||||
selfD.Closest = append(selfD.Closest, *info)
|
||||
}
|
||||
@@ -59,12 +59,12 @@ func (peer *PeerInfo) cmdAnouncement(msg *protocol.MessageAnnouncement, connecti
|
||||
// FIND_PEER: Find a different peer?
|
||||
if msg.Actions&(1<<protocol.ActionFindPeer) > 0 && len(msg.FindPeerKeys) > 0 {
|
||||
for _, findPeer := range msg.FindPeerKeys {
|
||||
Filters.IncomingRequest(peer, protocol.ActionFindPeer, findPeer.Hash, nil)
|
||||
peer.Backend.Filters.IncomingRequest(peer, protocol.ActionFindPeer, findPeer.Hash, nil)
|
||||
|
||||
details := protocol.Hash2Peer{ID: findPeer}
|
||||
|
||||
// Same as before, put self as ignoredNodes.
|
||||
for _, node := range nodesDHT.GetClosestContacts(respondClosesContactsCount, findPeer.Hash, filterFunc(connection.IsLocal(), allowIPv4, allowIPv6), peer.NodeID) {
|
||||
for _, node := range peer.Backend.nodesDHT.GetClosestContacts(respondClosesContactsCount, findPeer.Hash, filterFunc(connection.IsLocal(), allowIPv4, allowIPv6), peer.NodeID) {
|
||||
if info := node.Info.(*PeerInfo).peer2Record(connection.IsLocal(), allowIPv4, allowIPv6); info != nil {
|
||||
details.Closest = append(details.Closest, *info)
|
||||
}
|
||||
@@ -81,13 +81,13 @@ func (peer *PeerInfo) cmdAnouncement(msg *protocol.MessageAnnouncement, connecti
|
||||
// Find a value?
|
||||
if msg.Actions&(1<<protocol.ActionFindValue) > 0 {
|
||||
for _, findHash := range msg.FindDataKeys {
|
||||
Filters.IncomingRequest(peer, protocol.ActionFindValue, findHash.Hash, nil)
|
||||
peer.Backend.Filters.IncomingRequest(peer, protocol.ActionFindValue, findHash.Hash, nil)
|
||||
|
||||
stored, data := announcementGetData(findHash.Hash)
|
||||
stored, data := peer.announcementGetData(findHash.Hash)
|
||||
if stored && len(data) > 0 {
|
||||
filesEmbed = append(filesEmbed, protocol.EmbeddedFileData{ID: findHash, Data: data})
|
||||
} else if stored {
|
||||
selfRecord := selfPeerRecord()
|
||||
selfRecord := peer.Backend.selfPeerRecord()
|
||||
hash2Peers = append(hash2Peers, protocol.Hash2Peer{ID: findHash, Storing: []protocol.PeerRecord{selfRecord}})
|
||||
} else {
|
||||
hashesNotFound = append(hashesNotFound, findHash.Hash)
|
||||
@@ -98,7 +98,7 @@ func (peer *PeerInfo) cmdAnouncement(msg *protocol.MessageAnnouncement, connecti
|
||||
// Information about files stored by the sender?
|
||||
if msg.Actions&(1<<protocol.ActionInfoStore) > 0 && len(msg.InfoStoreFiles) > 0 {
|
||||
for n := range msg.InfoStoreFiles {
|
||||
Filters.IncomingRequest(peer, protocol.ActionInfoStore, msg.InfoStoreFiles[n].ID.Hash, &msg.InfoStoreFiles[n])
|
||||
peer.Backend.Filters.IncomingRequest(peer, protocol.ActionInfoStore, msg.InfoStoreFiles[n].ID.Hash, &msg.InfoStoreFiles[n])
|
||||
}
|
||||
|
||||
peer.announcementStore(msg.InfoStoreFiles)
|
||||
@@ -144,7 +144,7 @@ func (peer *PeerInfo) cmdResponse(msg *protocol.MessageResponse, connection *Con
|
||||
if msg.SequenceInfo == nil || msg.SequenceInfo.Data == nil {
|
||||
// If there is no sequence data but there were results returned, it means we received unsolicited response data. It will be rejected.
|
||||
if len(msg.HashesNotFound) > 0 || len(msg.Hash2Peers) > 0 || len(msg.FilesEmbed) > 0 {
|
||||
Filters.LogError("cmdResponse", "unsolicited response data received from %s\n", connection.Address.String())
|
||||
peer.Backend.Filters.LogError("cmdResponse", "unsolicited response data received from %s\n", connection.Address.String())
|
||||
}
|
||||
|
||||
return
|
||||
@@ -154,8 +154,8 @@ func (peer *PeerInfo) cmdResponse(msg *protocol.MessageResponse, connection *Con
|
||||
if _, ok := msg.SequenceInfo.Data.(*bootstrapFindSelf); ok {
|
||||
for _, hash2Peer := range msg.Hash2Peers {
|
||||
// Make sure no garbage is returned. The key must be self and only Closest is expected.
|
||||
if !bytes.Equal(hash2Peer.ID.Hash, nodeID) || len(hash2Peer.Closest) == 0 {
|
||||
Filters.LogError("cmdResponse", "incoming response to bootstrap FIND_SELF contains invalid data from %s\n", connection.Address.String())
|
||||
if !bytes.Equal(hash2Peer.ID.Hash, peer.Backend.nodeID) || len(hash2Peer.Closest) == 0 {
|
||||
peer.Backend.Filters.LogError("cmdResponse", "incoming response to bootstrap FIND_SELF contains invalid data from %s\n", connection.Address.String())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ func (peer *PeerInfo) cmdResponse(msg *protocol.MessageResponse, connection *Con
|
||||
}
|
||||
|
||||
for _, hash2Peer := range msg.Hash2Peers {
|
||||
info.QueueResult(&dht.NodeMessage{SenderID: peer.NodeID, Closest: records2Nodes(hash2Peer.Closest, peer), Storing: records2Nodes(hash2Peer.Storing, peer)})
|
||||
info.QueueResult(&dht.NodeMessage{SenderID: peer.NodeID, Closest: peer.records2Nodes(hash2Peer.Closest), Storing: peer.records2Nodes(hash2Peer.Storing)})
|
||||
|
||||
if hash2Peer.IsLast {
|
||||
info.Done()
|
||||
@@ -203,7 +203,7 @@ func (peer *PeerInfo) cmdPing(msg *protocol.MessageRaw, connection *Connection)
|
||||
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandPong, Sequence: msg.Sequence}
|
||||
|
||||
Filters.MessageOutPong(peer, raw)
|
||||
peer.Backend.Filters.MessageOutPong(peer, raw)
|
||||
|
||||
peer.send(raw)
|
||||
}
|
||||
@@ -231,8 +231,8 @@ func (peer *PeerInfo) cmdLocalDiscovery(msg *protocol.MessageAnnouncement, conne
|
||||
}
|
||||
|
||||
// SendChatAll sends a text message to all peers
|
||||
func SendChatAll(text string) {
|
||||
for _, peer := range PeerlistGet() {
|
||||
func (backend *Backend) SendChatAll(text string) {
|
||||
for _, peer := range backend.PeerlistGet() {
|
||||
peer.Chat(text)
|
||||
}
|
||||
}
|
||||
@@ -247,7 +247,7 @@ func (peer *PeerInfo) cmdTransfer(msg *protocol.MessageTransfer, connection *Con
|
||||
switch msg.Control {
|
||||
case protocol.TransferControlRequestStart:
|
||||
// First check if the file available in the warehouse.
|
||||
_, fileInfo, status, _ := UserWarehouse.FileExists(msg.Hash)
|
||||
_, fileInfo, status, _ := peer.Backend.UserWarehouse.FileExists(msg.Hash)
|
||||
if status != warehouse.StatusOK {
|
||||
// File not available.
|
||||
peer.sendTransfer(nil, protocol.TransferControlNotAvailable, msg.TransferProtocol, msg.Hash, 0, 0, msg.Sequence)
|
||||
@@ -286,10 +286,10 @@ func (peer *PeerInfo) cmdGetBlock(msg *protocol.MessageGetBlock, connection *Con
|
||||
switch msg.Control {
|
||||
case protocol.GetBlockControlRequestStart:
|
||||
// Currently only support the local blockchain.
|
||||
if !msg.BlockchainPublicKey.IsEqual(peerPublicKey) {
|
||||
if !msg.BlockchainPublicKey.IsEqual(peer.Backend.peerPublicKey) {
|
||||
peer.sendGetBlock(nil, protocol.GetBlockControlNotAvailable, msg.BlockchainPublicKey, 0, 0, nil, msg.Sequence)
|
||||
return
|
||||
} else if _, height, _ := UserBlockchain.Header(); height == 0 {
|
||||
} else if _, height, _ := peer.Backend.UserBlockchain.Header(); height == 0 {
|
||||
peer.sendGetBlock(nil, protocol.GetBlockControlEmpty, msg.BlockchainPublicKey, 0, 0, nil, msg.Sequence)
|
||||
return
|
||||
} else if msg.LimitBlockCount == 0 {
|
||||
|
||||
105
Config.go
105
Config.go
@@ -17,9 +17,10 @@ import (
|
||||
)
|
||||
|
||||
// Version is the current core library version
|
||||
const Version = "Alpha 5/14.12.2021"
|
||||
const Version = "Alpha 6/28.12.2021"
|
||||
|
||||
var config struct {
|
||||
// Config defines the minimum required config for a Peernet client.
|
||||
type Config struct {
|
||||
// Locations of important files and folders
|
||||
LogFile string `yaml:"LogFile"` // Log file. It contains informational and error messages.
|
||||
BlockchainMain string `yaml:"BlockchainMain"` // Blockchain main stores the end-users blockchain data. It contains meta data of shared files, profile data, and social interactions.
|
||||
@@ -60,84 +61,74 @@ type peerSeed struct {
|
||||
Address []string `yaml:"Address"` // IP:Port
|
||||
}
|
||||
|
||||
var configFile string
|
||||
|
||||
//go:embed "Config Default.yaml"
|
||||
var defaultConfig []byte
|
||||
|
||||
// LoadConfig reads the YAML configuration file. If an error is returned, the application shall exit.
|
||||
// Status: 0 = Unknown error checking config file, 1 = Error reading config file, 2 = Error parsing config file, 3 = Success
|
||||
func LoadConfig(filename string) (status int, err error) {
|
||||
// LoadConfig reads the YAML configuration file and unmarshals it into the provided structure.
|
||||
// If the config file does not exist or is empty, it will fall back to the default config which is hardcoded.
|
||||
// Status is of type ExitX.
|
||||
func LoadConfig(Filename string, ConfigOut interface{}) (status int, err error) {
|
||||
var configData []byte
|
||||
configFile = filename
|
||||
|
||||
// check if the file is non existent or empty
|
||||
stats, err := os.Stat(filename)
|
||||
if err != nil && os.IsNotExist(err) || err == nil && stats.Size() == 0 {
|
||||
configData = defaultConfig
|
||||
} else if err != nil {
|
||||
return 0, err
|
||||
} else if configData, err = ioutil.ReadFile(filename); err != nil {
|
||||
return 1, err
|
||||
}
|
||||
|
||||
// parse the config
|
||||
err = yaml.Unmarshal(configData, &config)
|
||||
if err != nil {
|
||||
return 2, err
|
||||
}
|
||||
|
||||
return 3, nil
|
||||
}
|
||||
|
||||
// LoadConfigOut is similar to LoadConfig but unmarshals the config into a caller provided structure.
|
||||
func LoadConfigOut(Filename string, ConfigOut interface{}) (status int, err error) {
|
||||
var configData []byte
|
||||
configFile = Filename
|
||||
|
||||
// check if the file is non existent or empty
|
||||
stats, err := os.Stat(Filename)
|
||||
if err != nil && os.IsNotExist(err) || err == nil && stats.Size() == 0 {
|
||||
configData = defaultConfig
|
||||
} else if err != nil {
|
||||
return 0, err
|
||||
return ExitErrorConfigAccess, err
|
||||
} else if configData, err = ioutil.ReadFile(Filename); err != nil {
|
||||
return 1, err
|
||||
return ExitErrorConfigRead, err
|
||||
}
|
||||
|
||||
// parse the config
|
||||
if err = yaml.Unmarshal(configData, &config); err != nil {
|
||||
return 2, err
|
||||
}
|
||||
if err = yaml.Unmarshal(configData, ConfigOut); err != nil {
|
||||
return 2, err
|
||||
err = yaml.Unmarshal(configData, ConfigOut)
|
||||
if err != nil {
|
||||
return ExitErrorConfigParse, err
|
||||
}
|
||||
|
||||
return 3, nil
|
||||
return ExitSuccess, nil
|
||||
}
|
||||
|
||||
func saveConfig() {
|
||||
data, err := yaml.Marshal(config)
|
||||
// SaveConfig stores the config.
|
||||
func SaveConfig(Filename string, Config interface{}) (err error) {
|
||||
data, err := yaml.Marshal(Config)
|
||||
if err != nil {
|
||||
Filters.LogError("saveConfig", "marshalling config: %v\n", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(Filename, data, 0666)
|
||||
}
|
||||
|
||||
// SaveConfig stores the current runtime config to file. Any foreign settings not present in the Config structure will be deleted.
|
||||
func (backend *Backend) SaveConfig() {
|
||||
if err := SaveConfig(backend.ConfigFilename, *backend.Config); err != nil {
|
||||
backend.Filters.LogError("SaveConfig", "writing config '%s': %v\n", backend.ConfigFilename, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (backend *Backend) configUpdateSeedList() {
|
||||
// parse the embedded config
|
||||
var configD Config
|
||||
if err := yaml.Unmarshal(defaultConfig, &configD); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(configFile, data, 0666)
|
||||
if err != nil {
|
||||
Filters.LogError("saveConfig", "writing config '%s': %v\n", configFile, err.Error())
|
||||
return
|
||||
// check if the seed list needs an update
|
||||
if backend.Config.SeedListVersion < configD.SeedListVersion {
|
||||
backend.Config.SeedList = configD.SeedList
|
||||
backend.Config.SeedListVersion = configD.SeedListVersion
|
||||
backend.SaveConfig()
|
||||
}
|
||||
}
|
||||
|
||||
// InitLog redirects subsequent log messages into the default log file specified in the configuration
|
||||
func InitLog() (err error) {
|
||||
func (backend *Backend) initLog() (err error) {
|
||||
// create the directory to the log file if specified
|
||||
if directory, _ := path.Split(config.LogFile); directory != "" {
|
||||
if directory, _ := path.Split(backend.Config.LogFile); directory != "" {
|
||||
os.MkdirAll(directory, os.ModePerm)
|
||||
}
|
||||
|
||||
logFile, err := os.OpenFile(config.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) // 666 : All uses can read/write
|
||||
logFile, err := os.OpenFile(backend.Config.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) // 666 : All uses can read/write
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -148,17 +139,3 @@ func InitLog() (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func configUpdateSeedList() {
|
||||
// parse the embedded config
|
||||
configD := config
|
||||
if err := yaml.Unmarshal(defaultConfig, &configD); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if config.SeedListVersion < configD.SeedListVersion {
|
||||
config.SeedList = configD.SeedList
|
||||
config.SeedListVersion = configD.SeedListVersion
|
||||
saveConfig()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ type Connection struct {
|
||||
RoundTripTime time.Duration // Full round-trip time of last reply.
|
||||
Firewall bool // Whether the remote peer indicates a potential firewall. This means a Traverse message shall be sent to establish a connection.
|
||||
traversePeer *PeerInfo // Temporary peer that may act as proxy for a Traverse message used for the first packet. This is used to establish this Connection to a peer that is behind a NAT or firewall.
|
||||
backend *Backend
|
||||
}
|
||||
|
||||
// Connection status
|
||||
@@ -190,7 +191,7 @@ func (peer *PeerInfo) registerConnection(incoming *Connection) (result *Connecti
|
||||
peer.connectionActive = append(peer.connectionActive, incoming)
|
||||
peer.setConnectionLatest(incoming)
|
||||
|
||||
Filters.NewPeerConnection(peer, incoming)
|
||||
peer.Backend.Filters.NewPeerConnection(peer, incoming)
|
||||
|
||||
return incoming
|
||||
}
|
||||
@@ -343,9 +344,9 @@ func (c *Connection) send(packet *protocol.PacketRaw, receiverPublicKey *btcec.P
|
||||
packet.Protocol = protocol.ProtocolVersion
|
||||
packet.SetSelfReportedPorts(c.Network.SelfReportedPorts())
|
||||
|
||||
Filters.PacketOut(packet, receiverPublicKey, c)
|
||||
c.backend.Filters.PacketOut(packet, receiverPublicKey, c)
|
||||
|
||||
raw, err := protocol.PacketEncrypt(peerPrivateKey, receiverPublicKey, packet)
|
||||
raw, err := protocol.PacketEncrypt(c.backend.peerPrivateKey, receiverPublicKey, packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -366,7 +367,7 @@ func (c *Connection) send(packet *protocol.PacketRaw, receiverPublicKey *btcec.P
|
||||
func (peer *PeerInfo) send(packet *protocol.PacketRaw) (err error) {
|
||||
if peer.isVirtual { // special case for peers that were not contacted before
|
||||
for _, address := range peer.targetAddresses {
|
||||
networks.sendAllNetworks(peer.PublicKey, packet, &net.UDPAddr{IP: address.IP, Port: int(address.Port)}, address.PortInternal, peer.Features&(1<<protocol.FeatureFirewall) > 0, peer.traversePeer, nil)
|
||||
peer.Backend.networks.sendAllNetworks(peer.PublicKey, packet, &net.UDPAddr{IP: address.IP, Port: int(address.Port)}, address.PortInternal, peer.Features&(1<<protocol.FeatureFirewall) > 0, peer.traversePeer, nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -443,7 +444,7 @@ func (nets *Networks) sendAllNetworks(receiverPublicKey *btcec.PublicKey, packet
|
||||
if sequenceData != nil {
|
||||
packet.Sequence = nets.Sequences.ArbitrarySequence(receiverPublicKey, sequenceData).SequenceNumber
|
||||
}
|
||||
err = (&Connection{Network: network, Address: remote, PortInternal: receiverPortInternal, traversePeer: traversePeer, Firewall: receiverFirewall}).send(packet, receiverPublicKey, isFirstPacket)
|
||||
err = (&Connection{backend: nets.backend, Network: network, Address: remote, PortInternal: receiverPortInternal, traversePeer: traversePeer, Firewall: receiverFirewall}).send(packet, receiverPublicKey, isFirstPacket)
|
||||
isFirstPacket = false
|
||||
|
||||
if err == nil {
|
||||
|
||||
11
DHT Store.go
11
DHT Store.go
@@ -11,19 +11,16 @@ import (
|
||||
"github.com/PeernetOfficial/core/store"
|
||||
)
|
||||
|
||||
// dhtStore contains all key-value data served via DHT
|
||||
var dhtStore store.Store
|
||||
|
||||
// TODO: Via descriptors, files stored by other peers
|
||||
|
||||
func initStore() {
|
||||
dhtStore = store.NewMemoryStore()
|
||||
func (backend *Backend) initStore() {
|
||||
backend.dhtStore = store.NewMemoryStore()
|
||||
}
|
||||
|
||||
// announcementGetData returns data for an announcement
|
||||
func announcementGetData(hash []byte) (stored bool, data []byte) {
|
||||
func (peer *PeerInfo) announcementGetData(hash []byte) (stored bool, data []byte) {
|
||||
// TODO: Create RetrieveIfSize to prevent files larger than EmbeddedFileSizeMax from being loaded
|
||||
data, found := dhtStore.Get(hash)
|
||||
data, found := peer.Backend.dhtStore.Get(hash)
|
||||
if !found {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
56
Filter.go
56
Filter.go
@@ -18,7 +18,7 @@ import (
|
||||
|
||||
// Filters contains all functions to install the hook. Use nil for unused.
|
||||
// The functions are called sequentially and block execution; if the filter takes a long time it should start a Go routine.
|
||||
var Filters struct {
|
||||
type Filters struct {
|
||||
// NewPeer is called every time a new peer, that is one that is not currently in the peer list.
|
||||
// Note that peers might be removed from peer lists and reappear quickly, i.e. this function may be called multiple times for the same peers.
|
||||
// The filter must maintain its own map of unique peer IDs if actual uniqueness of new peers is desired.
|
||||
@@ -64,51 +64,51 @@ var Filters struct {
|
||||
MessageOutPong func(peer *PeerInfo, packet *protocol.PacketRaw)
|
||||
}
|
||||
|
||||
func initFilters() {
|
||||
func (backend *Backend) initFilters() {
|
||||
// Set default filters to blank functions so they can be safely called without constant nil checks.
|
||||
// Only if not already set before init.
|
||||
|
||||
if Filters.NewPeer == nil {
|
||||
Filters.NewPeer = func(peer *PeerInfo, connection *Connection) {}
|
||||
if backend.Filters.NewPeer == nil {
|
||||
backend.Filters.NewPeer = func(peer *PeerInfo, connection *Connection) {}
|
||||
}
|
||||
if Filters.NewPeerConnection == nil {
|
||||
Filters.NewPeerConnection = func(peer *PeerInfo, connection *Connection) {}
|
||||
if backend.Filters.NewPeerConnection == nil {
|
||||
backend.Filters.NewPeerConnection = func(peer *PeerInfo, connection *Connection) {}
|
||||
}
|
||||
if Filters.DHTSearchStatus == nil {
|
||||
Filters.DHTSearchStatus = func(client *dht.SearchClient, function, format string, v ...interface{}) {}
|
||||
if backend.Filters.DHTSearchStatus == nil {
|
||||
backend.Filters.DHTSearchStatus = func(client *dht.SearchClient, function, format string, v ...interface{}) {}
|
||||
}
|
||||
if Filters.LogError == nil {
|
||||
Filters.LogError = DefaultLogError
|
||||
if backend.Filters.LogError == nil {
|
||||
backend.Filters.LogError = DefaultLogError
|
||||
}
|
||||
if Filters.IncomingRequest == nil {
|
||||
Filters.IncomingRequest = func(peer *PeerInfo, Action int, Key []byte, Info interface{}) {}
|
||||
if backend.Filters.IncomingRequest == nil {
|
||||
backend.Filters.IncomingRequest = func(peer *PeerInfo, Action int, Key []byte, Info interface{}) {}
|
||||
}
|
||||
if Filters.PacketIn == nil {
|
||||
Filters.PacketIn = func(packet *protocol.PacketRaw, senderPublicKey *btcec.PublicKey, c *Connection) {}
|
||||
if backend.Filters.PacketIn == nil {
|
||||
backend.Filters.PacketIn = func(packet *protocol.PacketRaw, senderPublicKey *btcec.PublicKey, c *Connection) {}
|
||||
}
|
||||
if Filters.PacketOut == nil {
|
||||
Filters.PacketOut = func(packet *protocol.PacketRaw, receiverPublicKey *btcec.PublicKey, c *Connection) {}
|
||||
if backend.Filters.PacketOut == nil {
|
||||
backend.Filters.PacketOut = func(packet *protocol.PacketRaw, receiverPublicKey *btcec.PublicKey, c *Connection) {}
|
||||
}
|
||||
if Filters.MessageIn == nil {
|
||||
Filters.MessageIn = func(peer *PeerInfo, raw *protocol.MessageRaw, message interface{}) {}
|
||||
if backend.Filters.MessageIn == nil {
|
||||
backend.Filters.MessageIn = func(peer *PeerInfo, raw *protocol.MessageRaw, message interface{}) {}
|
||||
}
|
||||
if Filters.MessageOutAnnouncement == nil {
|
||||
Filters.MessageOutAnnouncement = func(receiverPublicKey *btcec.PublicKey, peer *PeerInfo, packet *protocol.PacketRaw, findSelf bool, findPeer []protocol.KeyHash, findValue []protocol.KeyHash, files []protocol.InfoStore) {
|
||||
if backend.Filters.MessageOutAnnouncement == nil {
|
||||
backend.Filters.MessageOutAnnouncement = func(receiverPublicKey *btcec.PublicKey, peer *PeerInfo, packet *protocol.PacketRaw, findSelf bool, findPeer []protocol.KeyHash, findValue []protocol.KeyHash, files []protocol.InfoStore) {
|
||||
}
|
||||
}
|
||||
if Filters.MessageOutResponse == nil {
|
||||
Filters.MessageOutResponse = func(peer *PeerInfo, packet *protocol.PacketRaw, hash2Peers []protocol.Hash2Peer, filesEmbed []protocol.EmbeddedFileData, hashesNotFound [][]byte) {
|
||||
if backend.Filters.MessageOutResponse == nil {
|
||||
backend.Filters.MessageOutResponse = func(peer *PeerInfo, packet *protocol.PacketRaw, hash2Peers []protocol.Hash2Peer, filesEmbed []protocol.EmbeddedFileData, hashesNotFound [][]byte) {
|
||||
}
|
||||
}
|
||||
if Filters.MessageOutTraverse == nil {
|
||||
Filters.MessageOutTraverse = func(peer *PeerInfo, packet *protocol.PacketRaw, embeddedPacket *protocol.PacketRaw, receiverEnd *btcec.PublicKey) {
|
||||
if backend.Filters.MessageOutTraverse == nil {
|
||||
backend.Filters.MessageOutTraverse = func(peer *PeerInfo, packet *protocol.PacketRaw, embeddedPacket *protocol.PacketRaw, receiverEnd *btcec.PublicKey) {
|
||||
}
|
||||
}
|
||||
if Filters.MessageOutPing == nil {
|
||||
Filters.MessageOutPing = func(peer *PeerInfo, packet *protocol.PacketRaw, connection *Connection) {}
|
||||
if backend.Filters.MessageOutPing == nil {
|
||||
backend.Filters.MessageOutPing = func(peer *PeerInfo, packet *protocol.PacketRaw, connection *Connection) {}
|
||||
}
|
||||
if Filters.MessageOutPong == nil {
|
||||
Filters.MessageOutPong = func(peer *PeerInfo, packet *protocol.PacketRaw) {}
|
||||
if backend.Filters.MessageOutPong == nil {
|
||||
backend.Filters.MessageOutPong = func(peer *PeerInfo, packet *protocol.PacketRaw) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
74
Kademlia.go
74
Kademlia.go
@@ -17,13 +17,11 @@ import (
|
||||
const alpha = 5 // Count of nodes to be contacted in parallel for finding a key
|
||||
const bucketSize = 20 // Count of nodes per bucket
|
||||
|
||||
var nodesDHT *dht.DHT
|
||||
|
||||
func initKademlia() {
|
||||
nodesDHT = dht.NewDHT(&dht.Node{ID: nodeID}, 256, bucketSize, alpha)
|
||||
func (backend *Backend) initKademlia() {
|
||||
backend.nodesDHT = dht.NewDHT(&dht.Node{ID: backend.nodeID}, 256, bucketSize, alpha)
|
||||
|
||||
// ShouldEvict determines whether node 1 shall be evicted in favor of node 2
|
||||
nodesDHT.ShouldEvict = func(node1, node2 *dht.Node) bool {
|
||||
backend.nodesDHT.ShouldEvict = func(node1, node2 *dht.Node) bool {
|
||||
rttOld := node1.Info.(*PeerInfo).GetRTT()
|
||||
rttNew := node2.Info.(*PeerInfo).GetRTT()
|
||||
|
||||
@@ -36,33 +34,33 @@ func initKademlia() {
|
||||
}
|
||||
|
||||
// If here, none has a RTT. Keep the closer (by distance) one.
|
||||
return nodesDHT.IsNodeCloser(node1.ID, node2.ID)
|
||||
return backend.nodesDHT.IsNodeCloser(node1.ID, node2.ID)
|
||||
}
|
||||
|
||||
// SendRequestStore sends a store message to the remote node. I.e. asking it to store the given key-value
|
||||
nodesDHT.SendRequestStore = func(node *dht.Node, key []byte, dataSize uint64) {
|
||||
backend.nodesDHT.SendRequestStore = func(node *dht.Node, key []byte, dataSize uint64) {
|
||||
node.Info.(*PeerInfo).sendAnnouncementStore(key, dataSize)
|
||||
}
|
||||
|
||||
// SendRequestFindNode sends an information request to find a particular node. nodes are the nodes to send the request to.
|
||||
nodesDHT.SendRequestFindNode = func(request *dht.InformationRequest) {
|
||||
backend.nodesDHT.SendRequestFindNode = func(request *dht.InformationRequest) {
|
||||
for _, node := range request.Nodes {
|
||||
node.Info.(*PeerInfo).sendAnnouncementFindNode(request)
|
||||
}
|
||||
}
|
||||
|
||||
// SendRequestFindValue sends an information request to find data. nodes are the nodes to send the request to.
|
||||
nodesDHT.SendRequestFindValue = func(request *dht.InformationRequest) {
|
||||
backend.nodesDHT.SendRequestFindValue = func(request *dht.InformationRequest) {
|
||||
for _, node := range request.Nodes {
|
||||
node.Info.(*PeerInfo).sendAnnouncementFindValue(request)
|
||||
}
|
||||
}
|
||||
|
||||
nodesDHT.FilterSearchStatus = Filters.DHTSearchStatus
|
||||
backend.nodesDHT.FilterSearchStatus = backend.Filters.DHTSearchStatus
|
||||
}
|
||||
|
||||
// autoBucketRefresh refreshes buckets every 5 minutes to meet the alpha nodes per bucket target. Force full refresh every hour.
|
||||
func autoBucketRefresh() {
|
||||
func (backend *Backend) autoBucketRefresh() {
|
||||
for minute := 5; ; minute += 5 {
|
||||
time.Sleep(time.Minute * 5)
|
||||
|
||||
@@ -71,28 +69,28 @@ func autoBucketRefresh() {
|
||||
target = 0
|
||||
}
|
||||
|
||||
nodesDHT.RefreshBuckets(target)
|
||||
backend.nodesDHT.RefreshBuckets(target)
|
||||
}
|
||||
}
|
||||
|
||||
// bootstrapKademlia bootstraps the Kademlia bucket list
|
||||
func bootstrapKademlia() {
|
||||
func (backend *Backend) bootstrapKademlia() {
|
||||
monitor := make(chan *PeerInfo)
|
||||
registerPeerMonitor(monitor)
|
||||
backend.registerPeerMonitor(monitor)
|
||||
|
||||
// Wait until there are at least 2 peers connected.
|
||||
for {
|
||||
<-monitor
|
||||
if nodesDHT.NumNodes() >= 2 {
|
||||
if backend.nodesDHT.NumNodes() >= 2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
unregisterPeerMonitor(monitor)
|
||||
backend.unregisterPeerMonitor(monitor)
|
||||
|
||||
// Refresh every 10 seconds 3 times
|
||||
for n := 0; n < 3; n++ {
|
||||
nodesDHT.RefreshBuckets(alpha)
|
||||
backend.nodesDHT.RefreshBuckets(alpha)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
@@ -102,7 +100,7 @@ func bootstrapKademlia() {
|
||||
|
||||
func (peer *PeerInfo) sendAnnouncementFindNode(request *dht.InformationRequest) {
|
||||
// If the key is self, send it as FIND_SELF
|
||||
if bytes.Equal(request.Key, nodeID) {
|
||||
if bytes.Equal(request.Key, peer.Backend.nodeID) {
|
||||
peer.sendAnnouncement(false, true, nil, nil, nil, request)
|
||||
} else {
|
||||
peer.sendAnnouncement(false, false, []protocol.KeyHash{{Hash: request.Key}}, nil, nil, request)
|
||||
@@ -132,46 +130,46 @@ func Data2Hash(data []byte) (hash []byte) {
|
||||
}
|
||||
|
||||
// GetData returns the requested data. It checks first the local store and then tries via DHT.
|
||||
func GetData(hash []byte) (data []byte, senderNodeID []byte, found bool) {
|
||||
if data, found = GetDataLocal(hash); found {
|
||||
return data, nodeID, found
|
||||
func (backend *Backend) GetData(hash []byte) (data []byte, senderNodeID []byte, found bool) {
|
||||
if data, found = backend.GetDataLocal(hash); found {
|
||||
return data, backend.nodeID, found
|
||||
}
|
||||
|
||||
return GetDataDHT(hash)
|
||||
return backend.GetDataDHT(hash)
|
||||
}
|
||||
|
||||
// GetDataLocal returns data from the local warehouse.
|
||||
func GetDataLocal(hash []byte) (data []byte, found bool) {
|
||||
return dhtStore.Get(hash)
|
||||
func (backend *Backend) GetDataLocal(hash []byte) (data []byte, found bool) {
|
||||
return backend.dhtStore.Get(hash)
|
||||
}
|
||||
|
||||
// GetDataDHT requests data via DHT
|
||||
func GetDataDHT(hash []byte) (data []byte, senderNodeID []byte, found bool) {
|
||||
data, senderNodeID, found, _ = nodesDHT.Get(hash)
|
||||
func (backend *Backend) GetDataDHT(hash []byte) (data []byte, senderNodeID []byte, found bool) {
|
||||
data, senderNodeID, found, _ = backend.nodesDHT.Get(hash)
|
||||
return data, senderNodeID, found
|
||||
}
|
||||
|
||||
// StoreDataLocal stores data into the local warehouse.
|
||||
func StoreDataLocal(data []byte) error {
|
||||
func (backend *Backend) StoreDataLocal(data []byte) error {
|
||||
key := protocol.HashData(data)
|
||||
return dhtStore.Set(key, data)
|
||||
return backend.dhtStore.Set(key, data)
|
||||
}
|
||||
|
||||
// StoreDataDHT stores data locally and informs closestCount peers in the DHT about it.
|
||||
// Remote peers may choose to keep a record (in case another peers asks) or mirror the full data.
|
||||
func StoreDataDHT(data []byte, closestCount int) error {
|
||||
func (backend *Backend) StoreDataDHT(data []byte, closestCount int) error {
|
||||
key := protocol.HashData(data)
|
||||
if err := dhtStore.Set(key, data); err != nil {
|
||||
if err := backend.dhtStore.Set(key, data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nodesDHT.Store(key, uint64(len(data)), closestCount)
|
||||
return backend.nodesDHT.Store(key, uint64(len(data)), closestCount)
|
||||
}
|
||||
|
||||
// ---- NODE FUNCTIONS ----
|
||||
|
||||
// IsNodeContact checks if the node is a contact in the local DHT routing table
|
||||
func IsNodeContact(nodeID []byte) (node *dht.Node, peer *PeerInfo) {
|
||||
node = nodesDHT.IsNodeContact(nodeID)
|
||||
func (backend *Backend) IsNodeContact(nodeID []byte) (node *dht.Node, peer *PeerInfo) {
|
||||
node = backend.nodesDHT.IsNodeContact(nodeID)
|
||||
if node == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -180,14 +178,14 @@ func IsNodeContact(nodeID []byte) (node *dht.Node, peer *PeerInfo) {
|
||||
}
|
||||
|
||||
// FindNode finds a node via the DHT
|
||||
func FindNode(nodeID []byte, Timeout time.Duration) (node *dht.Node, peer *PeerInfo, err error) {
|
||||
func (backend *Backend) FindNode(nodeID []byte, Timeout time.Duration) (node *dht.Node, peer *PeerInfo, err error) {
|
||||
// first check if in mirrored node list
|
||||
if peer = NodelistLookup(nodeID); peer != nil {
|
||||
if peer = backend.NodelistLookup(nodeID); peer != nil {
|
||||
return nil, peer, nil
|
||||
}
|
||||
|
||||
// Search the node via DHT.
|
||||
node, err = nodesDHT.FindNode(nodeID)
|
||||
node, err = backend.nodesDHT.FindNode(nodeID)
|
||||
if node == nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -200,6 +198,6 @@ func FindNode(nodeID []byte, Timeout time.Duration) (node *dht.Node, peer *PeerI
|
||||
// AsyncSearch creates an async search for the given key in the DHT.
|
||||
// Timeout is the total time the search may take, covering all information requests. TimeoutIR is the time an information request may take.
|
||||
// Alpha is the number of concurrent requests that will be performed.
|
||||
func AsyncSearch(Action int, Key []byte, Timeout, TimeoutIR time.Duration, Alpha int) (client *dht.SearchClient) {
|
||||
return nodesDHT.NewSearch(Action, Key, Timeout, TimeoutIR, Alpha)
|
||||
func (backend *Backend) AsyncSearch(Action int, Key []byte, Timeout, TimeoutIR time.Duration, Alpha int) (client *dht.SearchClient) {
|
||||
return backend.nodesDHT.NewSearch(Action, Key, Timeout, TimeoutIR, Alpha)
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
|
||||
// pingConnection sends a ping to the target peer via the specified connection
|
||||
func (peer *PeerInfo) pingConnection(connection *Connection) {
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandPing, Sequence: networks.Sequences.NewSequence(peer.PublicKey, &peer.messageSequence, nil).SequenceNumber}
|
||||
Filters.MessageOutPing(peer, raw, connection)
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandPing, Sequence: peer.Backend.networks.Sequences.NewSequence(peer.PublicKey, &peer.messageSequence, nil).SequenceNumber}
|
||||
peer.Backend.Filters.MessageOutPing(peer, raw, connection)
|
||||
|
||||
err := peer.sendConnection(raw, connection)
|
||||
connection.LastPingOut = time.Now()
|
||||
@@ -29,14 +29,14 @@ func (peer *PeerInfo) pingConnection(connection *Connection) {
|
||||
// pingConnectionAnnouncement sends an empty announcement via a particular connection.
|
||||
// It has the same effect as ping, but returns the blockchain version and height of the other peer in the Response message, which may be useful for keeping the global blockchain cache up to date.
|
||||
func (peer *PeerInfo) pingConnectionAnnouncement(connection *Connection) {
|
||||
_, blockchainHeight, blockchainVersion := UserBlockchain.Header()
|
||||
packets := protocol.EncodeAnnouncement(false, false, nil, nil, nil, FeatureSupport(), blockchainHeight, blockchainVersion, userAgent)
|
||||
_, blockchainHeight, blockchainVersion := peer.Backend.UserBlockchain.Header()
|
||||
packets := protocol.EncodeAnnouncement(false, false, nil, nil, nil, peer.Backend.FeatureSupport(), blockchainHeight, blockchainVersion, peer.Backend.userAgent)
|
||||
if len(packets) != 1 {
|
||||
return
|
||||
}
|
||||
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandAnnouncement, Payload: packets[0], Sequence: networks.Sequences.NewSequence(peer.PublicKey, &peer.messageSequence, nil).SequenceNumber}
|
||||
Filters.MessageOutAnnouncement(peer.PublicKey, peer, raw, false, nil, nil, nil)
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandAnnouncement, Payload: packets[0], Sequence: peer.Backend.networks.Sequences.NewSequence(peer.PublicKey, &peer.messageSequence, nil).SequenceNumber}
|
||||
peer.Backend.Filters.MessageOutAnnouncement(peer.PublicKey, peer, raw, false, nil, nil, nil)
|
||||
|
||||
err := peer.sendConnection(raw, connection)
|
||||
connection.LastPingOut = time.Now()
|
||||
@@ -49,7 +49,7 @@ func (peer *PeerInfo) pingConnectionAnnouncement(connection *Connection) {
|
||||
// Ping sends a ping. This function exists only for debugging purposes, it should not be used normally.
|
||||
// This ping is not used for uptime detection and the LastPingOut time in connections is not set.
|
||||
func (peer *PeerInfo) Ping() {
|
||||
peer.send(&protocol.PacketRaw{Command: protocol.CommandPing, Sequence: networks.Sequences.NewSequence(peer.PublicKey, &peer.messageSequence, nil).SequenceNumber})
|
||||
peer.send(&protocol.PacketRaw{Command: protocol.CommandPing, Sequence: peer.Backend.networks.Sequences.NewSequence(peer.PublicKey, &peer.messageSequence, nil).SequenceNumber})
|
||||
}
|
||||
|
||||
// Chat sends a text message
|
||||
@@ -59,24 +59,24 @@ func (peer *PeerInfo) Chat(text string) {
|
||||
|
||||
// sendAnnouncement sends the announcement message. It acquires a new sequence for each message.
|
||||
func (peer *PeerInfo) sendAnnouncement(sendUA, findSelf bool, findPeer []protocol.KeyHash, findValue []protocol.KeyHash, files []protocol.InfoStore, sequenceData interface{}) {
|
||||
_, blockchainHeight, blockchainVersion := UserBlockchain.Header()
|
||||
packets := protocol.EncodeAnnouncement(sendUA, findSelf, findPeer, findValue, files, FeatureSupport(), blockchainHeight, blockchainVersion, userAgent)
|
||||
_, blockchainHeight, blockchainVersion := peer.Backend.UserBlockchain.Header()
|
||||
packets := protocol.EncodeAnnouncement(sendUA, findSelf, findPeer, findValue, files, peer.Backend.FeatureSupport(), blockchainHeight, blockchainVersion, peer.Backend.userAgent)
|
||||
|
||||
for _, packet := range packets {
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandAnnouncement, Payload: packet, Sequence: networks.Sequences.NewSequence(peer.PublicKey, &peer.messageSequence, sequenceData).SequenceNumber}
|
||||
Filters.MessageOutAnnouncement(peer.PublicKey, peer, raw, findSelf, findPeer, findValue, files)
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandAnnouncement, Payload: packet, Sequence: peer.Backend.networks.Sequences.NewSequence(peer.PublicKey, &peer.messageSequence, sequenceData).SequenceNumber}
|
||||
peer.Backend.Filters.MessageOutAnnouncement(peer.PublicKey, peer, raw, findSelf, findPeer, findValue, files)
|
||||
peer.send(raw)
|
||||
}
|
||||
}
|
||||
|
||||
// sendResponse sends the response message
|
||||
func (peer *PeerInfo) sendResponse(sequence uint32, sendUA bool, hash2Peers []protocol.Hash2Peer, filesEmbed []protocol.EmbeddedFileData, hashesNotFound [][]byte) (err error) {
|
||||
_, blockchainHeight, blockchainVersion := UserBlockchain.Header()
|
||||
packets, err := protocol.EncodeResponse(sendUA, hash2Peers, filesEmbed, hashesNotFound, FeatureSupport(), blockchainHeight, blockchainVersion, userAgent)
|
||||
_, blockchainHeight, blockchainVersion := peer.Backend.UserBlockchain.Header()
|
||||
packets, err := protocol.EncodeResponse(sendUA, hash2Peers, filesEmbed, hashesNotFound, peer.Backend.FeatureSupport(), blockchainHeight, blockchainVersion, peer.Backend.userAgent)
|
||||
|
||||
for _, packet := range packets {
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandResponse, Payload: packet, Sequence: sequence}
|
||||
Filters.MessageOutResponse(peer, raw, hash2Peers, filesEmbed, hashesNotFound)
|
||||
peer.Backend.Filters.MessageOutResponse(peer, raw, hash2Peers, filesEmbed, hashesNotFound)
|
||||
peer.send(raw)
|
||||
}
|
||||
|
||||
@@ -89,26 +89,26 @@ func (peer *PeerInfo) sendTraverse(packet *protocol.PacketRaw, receiverEnd *btce
|
||||
// self-reported ports are not set, as this isn't sent via a specific network but a relay
|
||||
//packet.SetSelfReportedPorts(c.Network.SelfReportedPorts())
|
||||
|
||||
embeddedPacketRaw, err := protocol.PacketEncrypt(peerPrivateKey, receiverEnd, packet)
|
||||
embeddedPacketRaw, err := protocol.PacketEncrypt(peer.Backend.peerPrivateKey, receiverEnd, packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
packetRaw, err := protocol.EncodeTraverse(peerPrivateKey, embeddedPacketRaw, receiverEnd, peer.PublicKey)
|
||||
packetRaw, err := protocol.EncodeTraverse(peer.Backend.peerPrivateKey, embeddedPacketRaw, receiverEnd, peer.PublicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandTraverse, Payload: packetRaw}
|
||||
|
||||
Filters.MessageOutTraverse(peer, raw, packet, receiverEnd)
|
||||
peer.Backend.Filters.MessageOutTraverse(peer, raw, packet, receiverEnd)
|
||||
|
||||
return peer.send(raw)
|
||||
}
|
||||
|
||||
// sendTransfer sends a transfer message
|
||||
func (peer *PeerInfo) sendTransfer(data []byte, control, transferProtocol uint8, hash []byte, offset, limit uint64, sequenceNumber uint32) (err error) {
|
||||
packetRaw, err := protocol.EncodeTransfer(peerPrivateKey, data, control, transferProtocol, hash, offset, limit)
|
||||
packetRaw, err := protocol.EncodeTransfer(peer.Backend.peerPrivateKey, data, control, transferProtocol, hash, offset, limit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func (peer *PeerInfo) sendTransfer(data []byte, control, transferProtocol uint8,
|
||||
|
||||
// sendGetBlock sends a get block message
|
||||
func (peer *PeerInfo) sendGetBlock(data []byte, control uint8, blockchainPublicKey *btcec.PublicKey, limitBlockCount, maxBlockSize uint64, targetBlocks []protocol.BlockRange, sequenceNumber uint32) (err error) {
|
||||
packetRaw, err := protocol.EncodeGetBlock(peerPrivateKey, data, control, blockchainPublicKey, limitBlockCount, maxBlockSize, targetBlocks)
|
||||
packetRaw, err := protocol.EncodeGetBlock(peer.Backend.peerPrivateKey, data, control, blockchainPublicKey, limitBlockCount, maxBlockSize, targetBlocks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ const changeMonitorFrequency = 10
|
||||
// networkChangeMonitor() monitors for network changes to act accordingly
|
||||
func (nets *Networks) networkChangeMonitor() {
|
||||
// If manual IPs are entered, no need for monitoring for any network changes.
|
||||
if len(config.Listen) > 0 {
|
||||
if len(nets.backend.Config.Listen) > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ func (nets *Networks) networkChangeMonitor() {
|
||||
|
||||
interfaceList, err := net.Interfaces()
|
||||
if err != nil {
|
||||
Filters.LogError("networkChangeMonitor", "enumerating network adapters failed: %s\n", err.Error())
|
||||
nets.backend.Filters.LogError("networkChangeMonitor", "enumerating network adapters failed: %s\n", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ func (nets *Networks) networkChangeMonitor() {
|
||||
for _, iface := range interfaceList {
|
||||
addressesNew, err := iface.Addrs()
|
||||
if err != nil {
|
||||
Filters.LogError("networkChangeMonitor", "enumerating IPs for network adapter '%s': %s\n", iface.Name, err.Error())
|
||||
nets.backend.Filters.LogError("networkChangeMonitor", "enumerating IPs for network adapter '%s': %s\n", iface.Name, err.Error())
|
||||
continue
|
||||
}
|
||||
ifacesNew[iface.Name] = addressesNew
|
||||
@@ -168,7 +168,7 @@ func (nets *Networks) networkChangeMonitor() {
|
||||
|
||||
// networkChangeInterfaceNew is called when a new interface is detected
|
||||
func (nets *Networks) networkChangeInterfaceNew(iface net.Interface, addresses []net.Addr) {
|
||||
Filters.LogError("networkChangeInterfaceNew", "new interface '%s' (%d IPs)\n", iface.Name, len(addresses))
|
||||
nets.backend.Filters.LogError("networkChangeInterfaceNew", "new interface '%s' (%d IPs)\n", iface.Name, len(addresses))
|
||||
|
||||
networksNew := nets.InterfaceStart(iface, addresses)
|
||||
|
||||
@@ -176,7 +176,7 @@ func (nets *Networks) networkChangeInterfaceNew(iface net.Interface, addresses [
|
||||
go network.upnpAuto()
|
||||
}
|
||||
|
||||
go nodesDHT.RefreshBuckets(0)
|
||||
go nets.backend.nodesDHT.RefreshBuckets(0)
|
||||
}
|
||||
|
||||
// networkChangeInterfaceRemove is called when an existing interface is removed
|
||||
@@ -184,7 +184,7 @@ func (nets *Networks) networkChangeInterfaceRemove(iface string, addresses []net
|
||||
nets.RLock()
|
||||
defer nets.RUnlock()
|
||||
|
||||
Filters.LogError("networkChangeInterfaceRemove", "removing interface '%s' (%d IPs)\n", iface, len(addresses))
|
||||
nets.backend.Filters.LogError("networkChangeInterfaceRemove", "removing interface '%s' (%d IPs)\n", iface, len(addresses))
|
||||
|
||||
for n, network := range nets.networks6 {
|
||||
if network.iface != nil && network.iface.Name == iface {
|
||||
@@ -215,7 +215,7 @@ func (nets *Networks) networkChangeInterfaceRemove(iface string, addresses []net
|
||||
|
||||
// networkChangeIPNew is called when an existing interface lists a new IP
|
||||
func (nets *Networks) networkChangeIPNew(iface net.Interface, address net.Addr) {
|
||||
Filters.LogError("networkChangeIPNew", "new interface '%s' IP %s\n", iface.Name, address.String())
|
||||
nets.backend.Filters.LogError("networkChangeIPNew", "new interface '%s' IP %s\n", iface.Name, address.String())
|
||||
|
||||
networksNew := nets.InterfaceStart(iface, []net.Addr{address})
|
||||
|
||||
@@ -223,7 +223,7 @@ func (nets *Networks) networkChangeIPNew(iface net.Interface, address net.Addr)
|
||||
go network.upnpAuto()
|
||||
}
|
||||
|
||||
go nodesDHT.RefreshBuckets(0)
|
||||
go nets.backend.nodesDHT.RefreshBuckets(0)
|
||||
}
|
||||
|
||||
// networkChangeIPRemove is called when an existing interface removes an IP
|
||||
@@ -231,7 +231,7 @@ func (nets *Networks) networkChangeIPRemove(iface net.Interface, address net.Add
|
||||
nets.RLock()
|
||||
defer nets.RUnlock()
|
||||
|
||||
Filters.LogError("networkChangeIPRemove", "remove interface '%s' IP %s\n", iface.Name, address.String())
|
||||
nets.backend.Filters.LogError("networkChangeIPRemove", "remove interface '%s' IP %s\n", iface.Name, address.String())
|
||||
|
||||
for n, network := range nets.networks6 {
|
||||
if network.address.IP.Equal(address.(*net.IPNet).IP) {
|
||||
|
||||
@@ -43,7 +43,7 @@ func (network *Network) BroadcastIPv4() (err error) {
|
||||
// listen on a special socket
|
||||
network.broadcastSocket, err = reuseport.ListenPacket("udp4", net.JoinHostPort(network.address.IP.String(), strconv.Itoa(ipv4BroadcastPort)))
|
||||
if err != nil {
|
||||
Filters.LogError("BroadcastIPv4", "broadcast socket listen on IP '%s' port '%d': %v\n", network.address.IP.String(), ipv4BroadcastPort, err)
|
||||
network.backend.Filters.LogError("BroadcastIPv4", "broadcast socket listen on IP '%s' port '%d': %v\n", network.address.IP.String(), ipv4BroadcastPort, err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -64,8 +64,8 @@ func (network *Network) BroadcastIPv4Listen() {
|
||||
length, sender, err := network.broadcastSocket.ReadFrom(buffer)
|
||||
|
||||
if err != nil {
|
||||
Filters.LogError("BroadcastIPv4Listen", "receiving UDP message: %v\n", err) // Only log for debug purposes.
|
||||
time.Sleep(time.Millisecond * 50) // In case of endless errors, prevent ddos of CPU.
|
||||
network.backend.Filters.LogError("BroadcastIPv4Listen", "receiving UDP message: %v\n", err) // Only log for debug purposes.
|
||||
time.Sleep(time.Millisecond * 50) // In case of endless errors, prevent ddos of CPU.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -92,13 +92,13 @@ func (network *Network) BroadcastIPv4Listen() {
|
||||
|
||||
// BroadcastIPv4Send sends out a single broadcast messages to discover peers
|
||||
func (network *Network) BroadcastIPv4Send() (err error) {
|
||||
_, blockchainHeight, blockchainVersion := UserBlockchain.Header()
|
||||
packets := protocol.EncodeAnnouncement(true, true, nil, nil, nil, FeatureSupport(), blockchainHeight, blockchainVersion, userAgent)
|
||||
_, blockchainHeight, blockchainVersion := network.backend.UserBlockchain.Header()
|
||||
packets := protocol.EncodeAnnouncement(true, true, nil, nil, nil, network.backend.FeatureSupport(), blockchainHeight, blockchainVersion, network.backend.userAgent)
|
||||
if len(packets) == 0 {
|
||||
return errors.New("error encoding broadcast announcement")
|
||||
}
|
||||
|
||||
raw, err := protocol.PacketEncrypt(peerPrivateKey, ipv4BroadcastPublicKey, &protocol.PacketRaw{Protocol: protocol.ProtocolVersion, Command: protocol.CommandLocalDiscovery, Payload: packets[0]})
|
||||
raw, err := protocol.PacketEncrypt(network.backend.peerPrivateKey, ipv4BroadcastPublicKey, &protocol.PacketRaw{Protocol: protocol.ProtocolVersion, Command: protocol.CommandLocalDiscovery, Payload: packets[0]})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -107,7 +107,7 @@ func (network *Network) BroadcastIPv4Send() (err error) {
|
||||
for _, ip := range network.broadcastIPv4 {
|
||||
err = network.send(ip, ipv4BroadcastPort, raw)
|
||||
if err != nil {
|
||||
Filters.LogError("BroadcastIPv4Send", "sending UDP packet: %v\n", err)
|
||||
network.backend.Filters.LogError("BroadcastIPv4Send", "sending UDP packet: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ func (network *Network) MulticastIPv6Join() (err error) {
|
||||
// listen on a special socket
|
||||
network.multicastSocket, err = reuseport.ListenPacket("udp6", net.JoinHostPort(network.address.IP.String(), strconv.Itoa(ipv6MulticastPort)))
|
||||
if err != nil {
|
||||
Filters.LogError("MulticastIPv6Join", "multicast socket listen on IP '%s' port '%d': %v\n", network.address.IP.String(), ipv6MulticastPort, err)
|
||||
network.backend.Filters.LogError("MulticastIPv6Join", "multicast socket listen on IP '%s' port '%d': %v\n", network.address.IP.String(), ipv6MulticastPort, err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func (network *Network) MulticastIPv6Join() (err error) {
|
||||
// receive messages from self or other processes running on the same computer
|
||||
if loop, err := pc.MulticastLoopback(); err == nil && !loop {
|
||||
if err := pc.SetMulticastLoopback(true); err != nil {
|
||||
Filters.LogError("MulticastIPv6Join", "setting multicast loopback status: %v\n", err)
|
||||
network.backend.Filters.LogError("MulticastIPv6Join", "setting multicast loopback status: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +108,8 @@ func (network *Network) MulticastIPv6Listen() {
|
||||
length, sender, err := network.multicastSocket.ReadFrom(buffer)
|
||||
|
||||
if err != nil {
|
||||
Filters.LogError("MulticastIPv6Listen", "receiving UDP message: %v\n", err) // Only log for debug purposes.
|
||||
time.Sleep(time.Millisecond * 50) // In case of endless errors, prevent ddos of CPU.
|
||||
network.backend.Filters.LogError("MulticastIPv6Listen", "receiving UDP message: %v\n", err) // Only log for debug purposes.
|
||||
time.Sleep(time.Millisecond * 50) // In case of endless errors, prevent ddos of CPU.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -137,13 +137,13 @@ func (network *Network) MulticastIPv6Listen() {
|
||||
|
||||
// MulticastIPv6Send sends out a single multicast messages to discover peers at the same site
|
||||
func (network *Network) MulticastIPv6Send() (err error) {
|
||||
_, blockchainHeight, blockchainVersion := UserBlockchain.Header()
|
||||
packets := protocol.EncodeAnnouncement(true, true, nil, nil, nil, FeatureSupport(), blockchainHeight, blockchainVersion, userAgent)
|
||||
_, blockchainHeight, blockchainVersion := network.backend.UserBlockchain.Header()
|
||||
packets := protocol.EncodeAnnouncement(true, true, nil, nil, nil, network.backend.FeatureSupport(), blockchainHeight, blockchainVersion, network.backend.userAgent)
|
||||
if len(packets) == 0 {
|
||||
return errors.New("error encoding multicast announcement")
|
||||
}
|
||||
|
||||
raw, err := protocol.PacketEncrypt(peerPrivateKey, ipv6MulticastPublicKey, &protocol.PacketRaw{Protocol: protocol.ProtocolVersion, Command: protocol.CommandLocalDiscovery, Payload: packets[0]})
|
||||
raw, err := protocol.PacketEncrypt(network.backend.peerPrivateKey, ipv6MulticastPublicKey, &protocol.PacketRaw{Protocol: protocol.ProtocolVersion, Command: protocol.CommandLocalDiscovery, Payload: packets[0]})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -31,33 +31,33 @@ type networkWire struct {
|
||||
}
|
||||
|
||||
// initNetwork sets up the network configuration and starts listening.
|
||||
func initNetwork() {
|
||||
func (backend *Backend) initNetwork() {
|
||||
rand.Seed(time.Now().UnixNano()) // we are not using "crypto/rand" for speed tradeoff
|
||||
|
||||
// start listen workers
|
||||
if config.ListenWorkers == 0 {
|
||||
config.ListenWorkers = 2
|
||||
if backend.Config.ListenWorkers == 0 {
|
||||
backend.Config.ListenWorkers = 2
|
||||
}
|
||||
for n := 0; n < config.ListenWorkers; n++ {
|
||||
go networks.packetWorker()
|
||||
for n := 0; n < backend.Config.ListenWorkers; n++ {
|
||||
go backend.networks.packetWorker()
|
||||
}
|
||||
|
||||
// check if user specified where to listen
|
||||
if len(config.Listen) > 0 {
|
||||
for _, listenA := range config.Listen {
|
||||
if len(backend.Config.Listen) > 0 {
|
||||
for _, listenA := range backend.Config.Listen {
|
||||
host, portA, err := net.SplitHostPort(listenA)
|
||||
if err != nil && strings.Contains(err.Error(), "missing port in address") { // port is optional
|
||||
host = listenA
|
||||
portA = "0"
|
||||
} else if err != nil {
|
||||
Filters.LogError("initNetwork", "invalid input listen address '%s': %s\n", listenA, err.Error())
|
||||
backend.Filters.LogError("initNetwork", "invalid input listen address '%s': %s\n", listenA, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
portI, _ := strconv.Atoi(portA)
|
||||
|
||||
if _, err := networks.PrepareListen(host, portI); err != nil {
|
||||
Filters.LogError("initNetwork", "listen on '%s': %s\n", listenA, err.Error())
|
||||
if _, err := backend.networks.PrepareListen(host, portI); err != nil {
|
||||
backend.Filters.LogError("initNetwork", "listen on '%s': %s\n", listenA, err.Error())
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -79,20 +79,20 @@ func initNetwork() {
|
||||
// * Network adapters and IPs might change. Simplest case is if someone changes Wifi network.
|
||||
interfaceList, err := net.Interfaces()
|
||||
if err != nil {
|
||||
Filters.LogError("initNetwork", "enumerating network adapters failed: %s\n", err.Error())
|
||||
backend.Filters.LogError("initNetwork", "enumerating network adapters failed: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, iface := range interfaceList {
|
||||
addresses, err := iface.Addrs()
|
||||
if err != nil {
|
||||
Filters.LogError("initNetwork", "enumerating IPs for network adapter '%s': %s\n", iface.Name, err.Error())
|
||||
backend.Filters.LogError("initNetwork", "enumerating IPs for network adapter '%s': %s\n", iface.Name, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
networks.ipListen.ifacesExist[iface.Name] = addresses
|
||||
backend.networks.ipListen.ifacesExist[iface.Name] = addresses
|
||||
|
||||
networks.InterfaceStart(iface, addresses)
|
||||
backend.networks.InterfaceStart(iface, addresses)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,13 +116,13 @@ func (nets *Networks) InterfaceStart(iface net.Interface, addresses []net.Addr)
|
||||
continue
|
||||
}
|
||||
|
||||
Filters.LogError("networks.InterfaceStart", "listening on network adapter '%s' IPv4 '%s': %s\n", iface.Name, net1.IP.String(), err.Error())
|
||||
nets.backend.Filters.LogError("networks.InterfaceStart", "listening on network adapter '%s' IPv4 '%s': %s\n", iface.Name, net1.IP.String(), err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
nets.ipListen.Add(networkNew.address)
|
||||
|
||||
Filters.LogError("networks.InterfaceStart", "listen on network '%s' UDP %s\n", iface.Name, networkNew.address.String())
|
||||
nets.backend.Filters.LogError("networks.InterfaceStart", "listen on network '%s' UDP %s\n", iface.Name, networkNew.address.String())
|
||||
|
||||
networksNew = append(networksNew, networkNew)
|
||||
}
|
||||
@@ -137,7 +137,7 @@ func (nets *Networks) PrepareListen(ipA string, port int) (network *Network, err
|
||||
return nil, errors.New("invalid input IP")
|
||||
}
|
||||
|
||||
network = &Network{networkGroup: nets}
|
||||
network = &Network{backend: nets.backend, networkGroup: nets}
|
||||
network.terminateSignal = make(chan interface{})
|
||||
|
||||
// get the network interface that belongs to the IP
|
||||
|
||||
@@ -33,10 +33,10 @@ func (nets *Networks) startUPnP() {
|
||||
}
|
||||
}
|
||||
|
||||
if config.PortForward > 0 {
|
||||
config.EnableUPnP = false
|
||||
if nets.backend.Config.PortForward > 0 {
|
||||
nets.backend.Config.EnableUPnP = false
|
||||
}
|
||||
if !config.EnableUPnP {
|
||||
if !nets.backend.Config.EnableUPnP {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ func isPrivateIP(ip net.IP) bool {
|
||||
|
||||
// upnpAuto runs a UPnP daemon to forward the port, refresh the forwarding and continuously monitor if the forwarding remains valid.
|
||||
func (network *Network) upnpAuto() {
|
||||
if !config.EnableUPnP || !network.upnpIsEligible() {
|
||||
if !network.backend.Config.EnableUPnP || !network.upnpIsEligible() {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ monitorLoop:
|
||||
}
|
||||
|
||||
// invalid :(
|
||||
Filters.LogError("upnpMonitorPortForward", "port forwarding invalidated for local IP %s (adapter %s) external IP %s port %d\n", network.address.String(), network.iface.Name, network.ipExternal.String(), network.portExternal)
|
||||
network.backend.Filters.LogError("upnpMonitorPortForward", "port forwarding invalidated for local IP %s (adapter %s) external IP %s port %d\n", network.address.String(), network.iface.Name, network.ipExternal.String(), network.portExternal)
|
||||
|
||||
network.portExternal = 0
|
||||
network.ipExternal = net.IP{}
|
||||
|
||||
53
Network.go
53
Network.go
@@ -35,6 +35,7 @@ type Network struct {
|
||||
terminateSignal chan interface{} // gets closed on termination signal, can be used in select via "case _ = <- network.terminateSignal:"
|
||||
sync.RWMutex // for sychronized closing
|
||||
networkGroup *Networks // Pointer to the pool of networks that this is part of
|
||||
backend *Backend
|
||||
}
|
||||
|
||||
// Default ports to use. This may be randomized in the future to prevent fingerprinting (and subsequent blocking) by corporate and ISP firewalls.
|
||||
@@ -115,8 +116,8 @@ func (network *Network) Listen() {
|
||||
return
|
||||
}
|
||||
|
||||
Filters.LogError("Listen", "receiving UDP message: %v\n", err) // Only log for debug purposes.
|
||||
time.Sleep(time.Millisecond * 50) // In case of endless errors, prevent ddos of CPU.
|
||||
network.backend.Filters.LogError("Listen", "receiving UDP message: %v\n", err) // Only log for debug purposes.
|
||||
time.Sleep(time.Millisecond * 50) // In case of endless errors, prevent ddos of CPU.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -126,7 +127,7 @@ func (network *Network) Listen() {
|
||||
}
|
||||
|
||||
// send the packet to a channel which is processed by multiple workers.
|
||||
network.networkGroup.rawPacketsIncoming <- networkWire{network: network, sender: sender, raw: buffer[:length], receiverPublicKey: peerPublicKey, unicast: true}
|
||||
network.networkGroup.rawPacketsIncoming <- networkWire{network: network, sender: sender, raw: buffer[:length], receiverPublicKey: network.backend.peerPublicKey, unicast: true}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +141,7 @@ func (nets *Networks) packetWorker() {
|
||||
}
|
||||
|
||||
// immediately discard message if sender = self
|
||||
if senderPublicKey.IsEqual(peerPublicKey) {
|
||||
if senderPublicKey.IsEqual(nets.backend.peerPublicKey) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -149,12 +150,12 @@ func (nets *Networks) packetWorker() {
|
||||
continue
|
||||
}
|
||||
|
||||
connection := &Connection{Network: packet.network, Address: packet.sender, Status: ConnectionActive}
|
||||
connection := &Connection{backend: nets.backend, Network: packet.network, Address: packet.sender, Status: ConnectionActive}
|
||||
|
||||
Filters.PacketIn(decoded, senderPublicKey, connection)
|
||||
nets.backend.Filters.PacketIn(decoded, senderPublicKey, connection)
|
||||
|
||||
// A peer structure will always be returned, even if the peer won't be added to the peer list.
|
||||
peer, added := PeerlistAdd(senderPublicKey, connection)
|
||||
peer, added := nets.backend.PeerlistAdd(senderPublicKey, connection)
|
||||
if !added {
|
||||
connection = peer.registerConnection(connection)
|
||||
}
|
||||
@@ -182,7 +183,7 @@ func (nets *Networks) packetWorker() {
|
||||
peer.BlockchainVersion = announce.BlockchainVersion
|
||||
peer.blockchainLastRefresh = time.Now()
|
||||
|
||||
Filters.MessageIn(peer, raw, announce)
|
||||
nets.backend.Filters.MessageIn(peer, raw, announce)
|
||||
|
||||
peer.cmdAnouncement(announce, connection)
|
||||
|
||||
@@ -218,7 +219,7 @@ func (nets *Networks) packetWorker() {
|
||||
peer.BlockchainVersion = response.BlockchainVersion
|
||||
peer.blockchainLastRefresh = time.Now()
|
||||
|
||||
Filters.MessageIn(peer, raw, response)
|
||||
nets.backend.Filters.MessageIn(peer, raw, response)
|
||||
|
||||
peer.cmdResponse(response, connection)
|
||||
|
||||
@@ -239,7 +240,7 @@ func (nets *Networks) packetWorker() {
|
||||
peer.BlockchainVersion = announce.BlockchainVersion
|
||||
peer.blockchainLastRefresh = time.Now()
|
||||
|
||||
Filters.MessageIn(peer, raw, announce)
|
||||
nets.backend.Filters.MessageIn(peer, raw, announce)
|
||||
|
||||
peer.cmdLocalDiscovery(announce, connection)
|
||||
|
||||
@@ -249,7 +250,7 @@ func (nets *Networks) packetWorker() {
|
||||
}
|
||||
|
||||
case protocol.CommandPing: // Ping
|
||||
Filters.MessageIn(peer, raw, nil)
|
||||
nets.backend.Filters.MessageIn(peer, raw, nil)
|
||||
peer.cmdPing(raw, connection)
|
||||
|
||||
case protocol.CommandPong: // Ping
|
||||
@@ -263,20 +264,20 @@ func (nets *Networks) packetWorker() {
|
||||
}
|
||||
raw.SequenceInfo = sequenceInfo
|
||||
|
||||
Filters.MessageIn(peer, raw, nil)
|
||||
nets.backend.Filters.MessageIn(peer, raw, nil)
|
||||
|
||||
peer.cmdPong(raw, connection)
|
||||
|
||||
case protocol.CommandChat: // Chat [debug]
|
||||
Filters.MessageIn(peer, raw, nil)
|
||||
nets.backend.Filters.MessageIn(peer, raw, nil)
|
||||
peer.cmdChat(raw, connection)
|
||||
|
||||
case protocol.CommandTraverse:
|
||||
if traverse, _ := protocol.DecodeTraverse(raw); traverse != nil {
|
||||
Filters.MessageIn(peer, raw, traverse)
|
||||
if traverse.TargetPeer.IsEqual(peerPublicKey) && traverse.AuthorizedRelayPeer.IsEqual(peer.PublicKey) {
|
||||
nets.backend.Filters.MessageIn(peer, raw, traverse)
|
||||
if traverse.TargetPeer.IsEqual(nets.backend.peerPublicKey) && traverse.AuthorizedRelayPeer.IsEqual(peer.PublicKey) {
|
||||
peer.cmdTraverseReceive(traverse)
|
||||
} else if traverse.AuthorizedRelayPeer.IsEqual(peerPublicKey) {
|
||||
} else if traverse.AuthorizedRelayPeer.IsEqual(nets.backend.peerPublicKey) {
|
||||
peer.cmdTraverseForward(traverse)
|
||||
}
|
||||
}
|
||||
@@ -314,7 +315,7 @@ func (nets *Networks) packetWorker() {
|
||||
}
|
||||
|
||||
default: // Unknown command
|
||||
Filters.MessageIn(peer, raw, nil)
|
||||
nets.backend.Filters.MessageIn(peer, raw, nil)
|
||||
|
||||
}
|
||||
|
||||
@@ -322,12 +323,12 @@ func (nets *Networks) packetWorker() {
|
||||
}
|
||||
|
||||
// GetNetworks returns the list of connected networks
|
||||
func GetNetworks(networkType int) (networksConnected []*Network) {
|
||||
func (backend *Backend) GetNetworks(networkType int) (networksConnected []*Network) {
|
||||
switch networkType {
|
||||
case 4:
|
||||
return networks.networks4
|
||||
return backend.networks.networks4
|
||||
case 6:
|
||||
return networks.networks6
|
||||
return backend.networks.networks6
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -383,22 +384,22 @@ func (network *Network) SelfReportedPorts() (portI, portE uint16) {
|
||||
// This external port will be then passed onto other peers who will use it to connect.
|
||||
portE = network.portExternal
|
||||
|
||||
if config.PortForward > 0 {
|
||||
portE = config.PortForward
|
||||
if network.backend.Config.PortForward > 0 {
|
||||
portE = network.backend.Config.PortForward
|
||||
}
|
||||
|
||||
return portI, portE
|
||||
}
|
||||
|
||||
// FeatureSupport returns supported features by this peer
|
||||
func FeatureSupport() (feature byte) {
|
||||
if networks.countListen4 > 0 {
|
||||
func (backend *Backend) FeatureSupport() (feature byte) {
|
||||
if backend.networks.countListen4 > 0 {
|
||||
feature |= 1 << protocol.FeatureIPv4Listen
|
||||
}
|
||||
if networks.countListen6 > 0 {
|
||||
if backend.networks.countListen6 > 0 {
|
||||
feature |= 1 << protocol.FeatureIPv6Listen
|
||||
}
|
||||
if networks.localFirewall {
|
||||
if backend.networks.localFirewall {
|
||||
feature |= 1 << protocol.FeatureFirewall
|
||||
}
|
||||
return feature
|
||||
|
||||
17
Networks.go
17
Networks.go
@@ -35,25 +35,26 @@ type Networks struct {
|
||||
|
||||
// localFirewall indicates if a local firewall may drop unsolicited incoming packets
|
||||
localFirewall bool
|
||||
|
||||
// backend
|
||||
backend *Backend
|
||||
}
|
||||
|
||||
// ReplyTimeout is the round-trip timeout for message sequences.
|
||||
const ReplyTimeout = 20
|
||||
|
||||
var networks *Networks
|
||||
func (backend *Backend) initMessageSequence() {
|
||||
backend.networks = &Networks{backend: backend}
|
||||
|
||||
func initMessageSequence() {
|
||||
networks = &Networks{}
|
||||
backend.networks.rawPacketsIncoming = make(chan networkWire, 1000) // buffer up to 1000 UDP packets before they get buffered by the OS network stack and eventually dropped
|
||||
|
||||
networks.rawPacketsIncoming = make(chan networkWire, 1000) // buffer up to 1000 UDP packets before they get buffered by the OS network stack and eventually dropped
|
||||
backend.networks.Sequences = protocol.NewSequenceManager(ReplyTimeout)
|
||||
|
||||
networks.Sequences = protocol.NewSequenceManager(ReplyTimeout)
|
||||
|
||||
networks.ipListen = NewIPList()
|
||||
backend.networks.ipListen = NewIPList()
|
||||
|
||||
// There is currently no suitable live firewall detection code. Instead, there is the config flag.
|
||||
// Windows: If the user runs as non-admin, it can be assumed that the Windows Firewall creates a rule to drop unsolicited incoming packets.
|
||||
// Changing the Windows Firewall (via netsh or otherwise) requires elevated admin rights.
|
||||
// This flag will be passed on to other peers to indicate that uncontacted peers shall use the Traverse message for establishing connections.
|
||||
networks.localFirewall = config.LocalFirewall
|
||||
backend.networks.localFirewall = backend.Config.LocalFirewall
|
||||
}
|
||||
|
||||
177
Peer ID.go
177
Peer ID.go
@@ -20,46 +20,40 @@ import (
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
)
|
||||
|
||||
// peerID is the current peers ID. It is a ECDSA (secp256k1) 257-bit public key.
|
||||
// The node ID is the blake3 hash of the public key compressed form.
|
||||
var peerPrivateKey *btcec.PrivateKey
|
||||
var peerPublicKey *btcec.PublicKey
|
||||
var nodeID []byte
|
||||
|
||||
func initPeerID() {
|
||||
peerList = make(map[[btcec.PubKeyBytesLenCompressed]byte]*PeerInfo)
|
||||
nodeList = make(map[[protocol.HashSize]byte]*PeerInfo)
|
||||
func (backend *Backend) initPeerID() {
|
||||
backend.peerList = make(map[[btcec.PubKeyBytesLenCompressed]byte]*PeerInfo)
|
||||
backend.nodeList = make(map[[protocol.HashSize]byte]*PeerInfo)
|
||||
|
||||
// load existing key from config, if available
|
||||
if len(config.PrivateKey) > 0 {
|
||||
configPK, err := hex.DecodeString(config.PrivateKey)
|
||||
if len(backend.Config.PrivateKey) > 0 {
|
||||
configPK, err := hex.DecodeString(backend.Config.PrivateKey)
|
||||
if err == nil {
|
||||
peerPrivateKey, peerPublicKey = btcec.PrivKeyFromBytes(btcec.S256(), configPK)
|
||||
nodeID = protocol.PublicKey2NodeID(peerPublicKey)
|
||||
backend.peerPrivateKey, backend.peerPublicKey = btcec.PrivKeyFromBytes(btcec.S256(), configPK)
|
||||
backend.nodeID = protocol.PublicKey2NodeID(backend.peerPublicKey)
|
||||
|
||||
if config.AutoUpdateSeedList {
|
||||
configUpdateSeedList()
|
||||
if backend.Config.AutoUpdateSeedList {
|
||||
backend.configUpdateSeedList()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Filters.LogError("initPeerID", "private key in config is corrupted! Error: %s\n", err.Error())
|
||||
backend.Filters.LogError("initPeerID", "private key in config is corrupted! Error: %s\n", err.Error())
|
||||
os.Exit(ExitPrivateKeyCorrupt)
|
||||
}
|
||||
|
||||
// if the peer ID is empty, create a new user public-private key pair
|
||||
var err error
|
||||
peerPrivateKey, peerPublicKey, err = Secp256k1NewPrivateKey()
|
||||
backend.peerPrivateKey, backend.peerPublicKey, err = Secp256k1NewPrivateKey()
|
||||
if err != nil {
|
||||
Filters.LogError("initPeerID", "generating public-private key pairs: %s\n", err.Error())
|
||||
backend.Filters.LogError("initPeerID", "generating public-private key pairs: %s\n", err.Error())
|
||||
os.Exit(ExitPrivateKeyCreate)
|
||||
}
|
||||
nodeID = protocol.PublicKey2NodeID(peerPublicKey)
|
||||
backend.nodeID = protocol.PublicKey2NodeID(backend.peerPublicKey)
|
||||
|
||||
// save the newly generated private key into the config
|
||||
config.PrivateKey = hex.EncodeToString(peerPrivateKey.Serialize())
|
||||
backend.Config.PrivateKey = hex.EncodeToString(backend.peerPrivateKey.Serialize())
|
||||
|
||||
saveConfig()
|
||||
backend.SaveConfig()
|
||||
}
|
||||
|
||||
// Secp256k1NewPrivateKey creates a new public-private key pair
|
||||
@@ -73,18 +67,18 @@ func Secp256k1NewPrivateKey() (privateKey *btcec.PrivateKey, publicKey *btcec.Pu
|
||||
}
|
||||
|
||||
// ExportPrivateKey returns the peers public and private key
|
||||
func ExportPrivateKey() (privateKey *btcec.PrivateKey, publicKey *btcec.PublicKey) {
|
||||
return peerPrivateKey, peerPublicKey
|
||||
func (backend *Backend) ExportPrivateKey() (privateKey *btcec.PrivateKey, publicKey *btcec.PublicKey) {
|
||||
return backend.peerPrivateKey, backend.peerPublicKey
|
||||
}
|
||||
|
||||
// SelfNodeID returns the node ID used for DHT
|
||||
func SelfNodeID() []byte {
|
||||
return nodeID
|
||||
func (backend *Backend) SelfNodeID() []byte {
|
||||
return backend.nodeID
|
||||
}
|
||||
|
||||
// SelfUserAgent returns the User Agent
|
||||
func SelfUserAgent() string {
|
||||
return userAgent
|
||||
func (backend *Backend) SelfUserAgent() string {
|
||||
return backend.userAgent
|
||||
}
|
||||
|
||||
// PeerInfo stores information about a single remote peer
|
||||
@@ -109,6 +103,8 @@ type PeerInfo struct {
|
||||
// statistics
|
||||
StatsPacketSent uint64 // Count of packets sent
|
||||
StatsPacketReceived uint64 // Count of packets received
|
||||
|
||||
Backend *Backend
|
||||
}
|
||||
|
||||
type peerAddress struct {
|
||||
@@ -117,79 +113,72 @@ type peerAddress struct {
|
||||
PortInternal uint16
|
||||
}
|
||||
|
||||
// peerList keeps track of all peers
|
||||
var peerList map[[btcec.PubKeyBytesLenCompressed]byte]*PeerInfo
|
||||
var peerlistMutex sync.RWMutex
|
||||
|
||||
// nodeList is a mirror of peerList but using the node ID
|
||||
var nodeList map[[protocol.HashSize]byte]*PeerInfo
|
||||
|
||||
// PeerlistAdd adds a new peer to the peer list. It does not validate the peer info. If the peer is already added, it does nothing. Connections must be live.
|
||||
func PeerlistAdd(PublicKey *btcec.PublicKey, connections ...*Connection) (peer *PeerInfo, added bool) {
|
||||
func (backend *Backend) PeerlistAdd(PublicKey *btcec.PublicKey, connections ...*Connection) (peer *PeerInfo, added bool) {
|
||||
if len(connections) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
publicKeyCompressed := publicKey2Compressed(PublicKey)
|
||||
|
||||
peerlistMutex.Lock()
|
||||
defer peerlistMutex.Unlock()
|
||||
backend.peerlistMutex.Lock()
|
||||
defer backend.peerlistMutex.Unlock()
|
||||
|
||||
peer, ok := peerList[publicKeyCompressed]
|
||||
peer, ok := backend.peerList[publicKeyCompressed]
|
||||
if ok {
|
||||
return peer, false
|
||||
}
|
||||
|
||||
peer = &PeerInfo{PublicKey: PublicKey, connectionActive: connections, connectionLatest: connections[0], NodeID: protocol.PublicKey2NodeID(PublicKey), messageSequence: rand.Uint32()}
|
||||
peer = &PeerInfo{Backend: backend, PublicKey: PublicKey, connectionActive: connections, connectionLatest: connections[0], NodeID: protocol.PublicKey2NodeID(PublicKey), messageSequence: rand.Uint32()}
|
||||
_, peer.IsRootPeer = rootPeers[publicKeyCompressed]
|
||||
|
||||
peerList[publicKeyCompressed] = peer
|
||||
backend.peerList[publicKeyCompressed] = peer
|
||||
|
||||
// also add to mirrored nodeList
|
||||
var nodeID [protocol.HashSize]byte
|
||||
copy(nodeID[:], peer.NodeID)
|
||||
nodeList[nodeID] = peer
|
||||
backend.nodeList[nodeID] = peer
|
||||
|
||||
// add to Kademlia
|
||||
nodesDHT.AddNode(&dht.Node{ID: peer.NodeID, Info: peer})
|
||||
backend.nodesDHT.AddNode(&dht.Node{ID: peer.NodeID, Info: peer})
|
||||
|
||||
// TODO: If the node isn't added to Kademlia, it should be either added temporarily to the peerList with an expiration, or to a temp list, or not at all.
|
||||
|
||||
// send to all channels non-blocking
|
||||
for _, monitor := range peerMonitor {
|
||||
for _, monitor := range backend.peerMonitor {
|
||||
select {
|
||||
case monitor <- peer:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
Filters.NewPeer(peer, connections[0])
|
||||
Filters.NewPeerConnection(peer, connections[0])
|
||||
backend.Filters.NewPeer(peer, connections[0])
|
||||
backend.Filters.NewPeerConnection(peer, connections[0])
|
||||
|
||||
return peer, true
|
||||
}
|
||||
|
||||
// PeerlistRemove removes a peer from the peer list.
|
||||
func PeerlistRemove(peer *PeerInfo) {
|
||||
peerlistMutex.Lock()
|
||||
defer peerlistMutex.Unlock()
|
||||
func (backend *Backend) PeerlistRemove(peer *PeerInfo) {
|
||||
backend.peerlistMutex.Lock()
|
||||
defer backend.peerlistMutex.Unlock()
|
||||
|
||||
// remove from Kademlia
|
||||
nodesDHT.RemoveNode(peer.NodeID)
|
||||
backend.nodesDHT.RemoveNode(peer.NodeID)
|
||||
|
||||
delete(peerList, publicKey2Compressed(peer.PublicKey))
|
||||
delete(backend.peerList, publicKey2Compressed(peer.PublicKey))
|
||||
|
||||
var nodeID [protocol.HashSize]byte
|
||||
copy(nodeID[:], peer.NodeID)
|
||||
|
||||
delete(nodeList, nodeID)
|
||||
delete(backend.nodeList, nodeID)
|
||||
}
|
||||
|
||||
// PeerlistGet returns the full peer list
|
||||
func PeerlistGet() (peers []*PeerInfo) {
|
||||
peerlistMutex.RLock()
|
||||
defer peerlistMutex.RUnlock()
|
||||
func (backend *Backend) PeerlistGet() (peers []*PeerInfo) {
|
||||
backend.peerlistMutex.RLock()
|
||||
defer backend.peerlistMutex.RUnlock()
|
||||
|
||||
for _, peer := range peerList {
|
||||
for _, peer := range backend.peerList {
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
|
||||
@@ -197,30 +186,30 @@ func PeerlistGet() (peers []*PeerInfo) {
|
||||
}
|
||||
|
||||
// PeerlistLookup returns the peer from the list with the public key
|
||||
func PeerlistLookup(publicKey *btcec.PublicKey) (peer *PeerInfo) {
|
||||
peerlistMutex.RLock()
|
||||
defer peerlistMutex.RUnlock()
|
||||
func (backend *Backend) PeerlistLookup(publicKey *btcec.PublicKey) (peer *PeerInfo) {
|
||||
backend.peerlistMutex.RLock()
|
||||
defer backend.peerlistMutex.RUnlock()
|
||||
|
||||
return peerList[publicKey2Compressed(publicKey)]
|
||||
return backend.peerList[publicKey2Compressed(publicKey)]
|
||||
}
|
||||
|
||||
// NodelistLookup returns the peer from the list with the node ID
|
||||
func NodelistLookup(nodeID []byte) (peer *PeerInfo) {
|
||||
peerlistMutex.RLock()
|
||||
defer peerlistMutex.RUnlock()
|
||||
func (backend *Backend) NodelistLookup(nodeID []byte) (peer *PeerInfo) {
|
||||
backend.peerlistMutex.RLock()
|
||||
defer backend.peerlistMutex.RUnlock()
|
||||
|
||||
var nodeID2 [protocol.HashSize]byte
|
||||
copy(nodeID2[:], nodeID)
|
||||
|
||||
return nodeList[nodeID2]
|
||||
return backend.nodeList[nodeID2]
|
||||
}
|
||||
|
||||
// PeerlistCount returns the current count of peers in the peer list
|
||||
func PeerlistCount() (count int) {
|
||||
peerlistMutex.RLock()
|
||||
defer peerlistMutex.RUnlock()
|
||||
func (backend *Backend) PeerlistCount() (count int) {
|
||||
backend.peerlistMutex.RLock()
|
||||
defer backend.peerlistMutex.RUnlock()
|
||||
|
||||
return len(peerList)
|
||||
return len(backend.peerList)
|
||||
}
|
||||
|
||||
func publicKey2Compressed(publicKey *btcec.PublicKey) [btcec.PubKeyBytesLenCompressed]byte {
|
||||
@@ -229,11 +218,11 @@ func publicKey2Compressed(publicKey *btcec.PublicKey) [btcec.PubKeyBytesLenCompr
|
||||
return key
|
||||
}
|
||||
|
||||
// records2Nodes translates infoPeer structures to nodes. If the reported nodes are not in the peer table, it will create temporary PeerInfo structures.
|
||||
// records2Nodes translates infoPeer structures to nodes reported by the peer. If the reported nodes are not in the peer table, it will create temporary PeerInfo structures.
|
||||
// LastContact is passed on in the Node.LastSeen field.
|
||||
func records2Nodes(records []protocol.PeerRecord, peerSource *PeerInfo) (nodes []*dht.Node) {
|
||||
func (peerSource *PeerInfo) records2Nodes(records []protocol.PeerRecord) (nodes []*dht.Node) {
|
||||
for _, record := range records {
|
||||
if isReturnedPeerBadQuality(&record) {
|
||||
if peerSource.Backend.isReturnedPeerBadQuality(&record) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -241,7 +230,7 @@ func records2Nodes(records []protocol.PeerRecord, peerSource *PeerInfo) (nodes [
|
||||
if record.PublicKey.IsEqual(peerSource.PublicKey) {
|
||||
// Special case if peer that stores info = sender. In that case IP:Port in the record would be empty anyway.
|
||||
peer = peerSource
|
||||
} else if peer = PeerlistLookup(record.PublicKey); peer == nil {
|
||||
} else if peer = peerSource.Backend.PeerlistLookup(record.PublicKey); peer == nil {
|
||||
// Create temporary peer which is not added to the global list and not added to Kademlia.
|
||||
// traversePeer is set to the peer who provided the node information.
|
||||
addresses := peerRecordToAddresses(&record)
|
||||
@@ -249,7 +238,7 @@ func records2Nodes(records []protocol.PeerRecord, peerSource *PeerInfo) (nodes [
|
||||
continue
|
||||
}
|
||||
|
||||
peer = &PeerInfo{PublicKey: record.PublicKey, connectionActive: nil, connectionLatest: nil, NodeID: protocol.PublicKey2NodeID(record.PublicKey), messageSequence: rand.Uint32(), isVirtual: true, targetAddresses: addresses, traversePeer: peerSource, Features: record.Features}
|
||||
peer = &PeerInfo{Backend: peerSource.Backend, PublicKey: record.PublicKey, connectionActive: nil, connectionLatest: nil, NodeID: protocol.PublicKey2NodeID(record.PublicKey), messageSequence: rand.Uint32(), isVirtual: true, targetAddresses: addresses, traversePeer: peerSource, Features: record.Features}
|
||||
}
|
||||
|
||||
nodes = append(nodes, &dht.Node{ID: peer.NodeID, LastSeen: record.LastContactT, Info: peer})
|
||||
@@ -259,55 +248,53 @@ func records2Nodes(records []protocol.PeerRecord, peerSource *PeerInfo) (nodes [
|
||||
}
|
||||
|
||||
// selfPeerRecord returns self as peer record
|
||||
func selfPeerRecord() (result protocol.PeerRecord) {
|
||||
func (backend *Backend) selfPeerRecord() (result protocol.PeerRecord) {
|
||||
return protocol.PeerRecord{
|
||||
PublicKey: peerPublicKey,
|
||||
NodeID: nodeID,
|
||||
PublicKey: backend.peerPublicKey,
|
||||
NodeID: backend.nodeID,
|
||||
//IP: network.address.IP,
|
||||
//Port: uint16(network.address.Port),
|
||||
LastContact: 0,
|
||||
Features: FeatureSupport(),
|
||||
Features: backend.FeatureSupport(),
|
||||
}
|
||||
}
|
||||
|
||||
var peerMonitor []chan<- *PeerInfo
|
||||
|
||||
// registerPeerMonitor registers a channel to receive all new peers
|
||||
func registerPeerMonitor(channel chan<- *PeerInfo) {
|
||||
peerlistMutex.Lock()
|
||||
defer peerlistMutex.Unlock()
|
||||
func (backend *Backend) registerPeerMonitor(channel chan<- *PeerInfo) {
|
||||
backend.peerlistMutex.Lock()
|
||||
defer backend.peerlistMutex.Unlock()
|
||||
|
||||
peerMonitor = append(peerMonitor, channel)
|
||||
backend.peerMonitor = append(backend.peerMonitor, channel)
|
||||
}
|
||||
|
||||
// unregisterPeerMonitor unregisters a channel
|
||||
func unregisterPeerMonitor(channel chan<- *PeerInfo) {
|
||||
peerlistMutex.Lock()
|
||||
defer peerlistMutex.Unlock()
|
||||
func (backend *Backend) unregisterPeerMonitor(channel chan<- *PeerInfo) {
|
||||
backend.peerlistMutex.Lock()
|
||||
defer backend.peerlistMutex.Unlock()
|
||||
|
||||
for n, channel2 := range peerMonitor {
|
||||
for n, channel2 := range backend.peerMonitor {
|
||||
if channel == channel2 {
|
||||
peerMonitorNew := peerMonitor[:n]
|
||||
if n < len(peerMonitor)-1 {
|
||||
peerMonitorNew = append(peerMonitorNew, peerMonitor[n+1:]...)
|
||||
peerMonitorNew := backend.peerMonitor[:n]
|
||||
if n < len(backend.peerMonitor)-1 {
|
||||
peerMonitorNew = append(peerMonitorNew, backend.peerMonitor[n+1:]...)
|
||||
}
|
||||
peerMonitor = peerMonitorNew
|
||||
backend.peerMonitor = peerMonitorNew
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteAccount deletes the account
|
||||
func DeleteAccount() {
|
||||
func (backend *Backend) DeleteAccount() {
|
||||
// delete the blockchain
|
||||
UserBlockchain.DeleteBlockchain()
|
||||
backend.UserBlockchain.DeleteBlockchain()
|
||||
|
||||
// delete the warehouse
|
||||
UserWarehouse.DeleteWarehouse()
|
||||
backend.UserWarehouse.DeleteWarehouse()
|
||||
|
||||
// delete the private key
|
||||
config.PrivateKey = ""
|
||||
saveConfig()
|
||||
backend.Config.PrivateKey = ""
|
||||
backend.SaveConfig()
|
||||
}
|
||||
|
||||
// PublicKeyFromPeerID decodes the peer ID (hex encoded) into a public key.
|
||||
|
||||
110
Peernet.go
110
Peernet.go
@@ -7,63 +7,105 @@ Author: Peter Kleissner
|
||||
package core
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/PeernetOfficial/core/blockchain"
|
||||
"github.com/PeernetOfficial/core/btcec"
|
||||
"github.com/PeernetOfficial/core/dht"
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
"github.com/PeernetOfficial/core/search"
|
||||
"github.com/PeernetOfficial/core/store"
|
||||
"github.com/PeernetOfficial/core/warehouse"
|
||||
)
|
||||
|
||||
var userAgent = "Peernet Core/0.1" // must be overwritten by the caller
|
||||
|
||||
// Init initializes the client. The config must be loaded first!
|
||||
// Init initializes the client. If the config file does not exist or is empty, a default one will be created.
|
||||
// The User Agent must be provided in the form "Application Name/1.0".
|
||||
func Init(UserAgent string) (backend *Backend) {
|
||||
if userAgent = UserAgent; userAgent == "" {
|
||||
// The returned status is of type ExitX. Anything other than ExitSuccess indicates a fatal failure.
|
||||
func Init(UserAgent string, ConfigFilename string, Filters *Filters) (backend *Backend, status int, err error) {
|
||||
if UserAgent == "" {
|
||||
return
|
||||
}
|
||||
|
||||
backend = &Backend{}
|
||||
currentBackend = backend
|
||||
backend = &Backend{
|
||||
ConfigFilename: ConfigFilename,
|
||||
userAgent: UserAgent,
|
||||
}
|
||||
|
||||
initFilters()
|
||||
initPeerID()
|
||||
initUserBlockchain()
|
||||
initUserWarehouse()
|
||||
initKademlia()
|
||||
initMessageSequence()
|
||||
initSeedList()
|
||||
if Filters != nil {
|
||||
backend.Filters = *Filters
|
||||
}
|
||||
|
||||
// The configuration and log init are fatal events if they fail.
|
||||
if status, err = LoadConfig(ConfigFilename, &backend.Config); status != ExitSuccess {
|
||||
return nil, status, err
|
||||
}
|
||||
|
||||
if err = backend.initLog(); err != nil {
|
||||
return nil, ExitErrorLogInit, err
|
||||
}
|
||||
|
||||
backend.initFilters()
|
||||
backend.initPeerID()
|
||||
backend.initUserBlockchain()
|
||||
backend.initUserWarehouse()
|
||||
backend.initKademlia()
|
||||
backend.initMessageSequence()
|
||||
backend.initSeedList()
|
||||
initMulticastIPv6()
|
||||
initBroadcastIPv4()
|
||||
initStore()
|
||||
initNetwork()
|
||||
backend.initStore()
|
||||
backend.initNetwork()
|
||||
backend.initBlockchainCache()
|
||||
|
||||
var err error
|
||||
|
||||
backend.GlobalBlockchainCache = initBlockchainCache(config.BlockchainGlobal, config.CacheMaxBlockSize, config.CacheMaxBlockCount, config.LimitTotalRecords)
|
||||
|
||||
if backend.SearchIndex, err = search.InitSearchIndexStore(config.SearchIndex); err != nil {
|
||||
Filters.LogError("Init", "search index '%s' init: %s", config.SearchIndex, err.Error())
|
||||
if backend.SearchIndex, err = search.InitSearchIndexStore(backend.Config.SearchIndex); err != nil {
|
||||
backend.Filters.LogError("Init", "search index '%s' init: %s", backend.Config.SearchIndex, err.Error())
|
||||
} else {
|
||||
backend.userBlockchainUpdateSearchIndex()
|
||||
}
|
||||
|
||||
return backend
|
||||
return backend, ExitSuccess, nil
|
||||
}
|
||||
|
||||
// Connect starts bootstrapping and local peer discovery.
|
||||
func Connect() {
|
||||
go bootstrapKademlia()
|
||||
go bootstrap()
|
||||
go networks.autoMulticastBroadcast()
|
||||
go autoPingAll()
|
||||
go networks.networkChangeMonitor()
|
||||
go networks.startUPnP()
|
||||
go autoBucketRefresh()
|
||||
func (backend *Backend) Connect() {
|
||||
go backend.bootstrapKademlia()
|
||||
go backend.bootstrap()
|
||||
go backend.networks.autoMulticastBroadcast()
|
||||
go backend.autoPingAll()
|
||||
go backend.networks.networkChangeMonitor()
|
||||
go backend.networks.startUPnP()
|
||||
go backend.autoBucketRefresh()
|
||||
}
|
||||
|
||||
// The Backend represents an instance of a Peernet client to be used by a frontend.
|
||||
// Global variables and init functions are to be merged.
|
||||
type Backend struct {
|
||||
ConfigFilename string // Filename of the configuration file.
|
||||
Config *Config // Config
|
||||
Filters Filters // Filters allow to install hooks.
|
||||
userAgent string // User Agent
|
||||
GlobalBlockchainCache *BlockchainCache // Caches blockchains of other peers.
|
||||
SearchIndex *search.SearchIndexStore // Search index of blockchain records.
|
||||
}
|
||||
networks *Networks // All connected networks.
|
||||
dhtStore store.Store // dhtStore contains all key-value data served via DHT
|
||||
UserBlockchain *blockchain.Blockchain // UserBlockchain is the user's blockchain and exports functions to directly read and write it
|
||||
UserWarehouse *warehouse.Warehouse // UserWarehouse is the user's warehouse for storing files that are shared
|
||||
nodesDHT *dht.DHT // Nodes connected in the DHT.
|
||||
|
||||
// This variable is to be replaced later by pointers in structures.
|
||||
var currentBackend *Backend
|
||||
// peerID is the current peer's ID. It is a ECDSA (secp256k1) 257-bit public key.
|
||||
peerPrivateKey *btcec.PrivateKey
|
||||
peerPublicKey *btcec.PublicKey
|
||||
|
||||
// The node ID is the blake3 hash of the public key compressed form.
|
||||
nodeID []byte
|
||||
|
||||
// peerList keeps track of all peers
|
||||
peerList map[[btcec.PubKeyBytesLenCompressed]byte]*PeerInfo
|
||||
peerlistMutex sync.RWMutex
|
||||
|
||||
// nodeList is a mirror of peerList but using the node ID
|
||||
nodeList map[[protocol.HashSize]byte]*PeerInfo
|
||||
|
||||
// peerMonitor is a list of channels receiving information about new peers
|
||||
peerMonitor []chan<- *PeerInfo
|
||||
}
|
||||
|
||||
4
Ping.go
4
Ping.go
@@ -24,7 +24,7 @@ const connectionInvalidate = 22
|
||||
const connectionRemove = 2 * 60
|
||||
|
||||
// autoPingAll sends out regular ping messages to all connections of all peers. This allows to detect invalid connections and eventually drop them.
|
||||
func autoPingAll() {
|
||||
func (backend *Backend) autoPingAll() {
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
thresholdInvalidate1 := time.Now().Add(-connectionInvalidate * time.Second)
|
||||
@@ -33,7 +33,7 @@ func autoPingAll() {
|
||||
thresholdPingOut2 := time.Now().Add(-pingTime * time.Second * 4)
|
||||
thresholdBlockchainRefresh := time.Now().Add(-thresholdBlockchainRefresh)
|
||||
|
||||
for _, peer := range PeerlistGet() {
|
||||
for _, peer := range backend.PeerlistGet() {
|
||||
// first handle active connections
|
||||
for _, connection := range peer.GetConnections(true) {
|
||||
thresholdPing := thresholdPingOut1
|
||||
|
||||
22
README.md
22
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
The core library which is needed for any Peernet application. It provides connectivity to the network and all basic functions. For details about Peernet see https://peernet.org/.
|
||||
|
||||
Current version: Alpha 5
|
||||
Current version: Alpha 6
|
||||
|
||||
## Use
|
||||
|
||||
@@ -11,25 +11,21 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/PeernetOfficial/core"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if status, err := core.LoadConfig("Config.yaml"); err != nil {
|
||||
fmt.Printf("Error loading config file: %s", err.Error())
|
||||
os.Exit(core.ExitErrorConfigAccess)
|
||||
func main() {
|
||||
backend, status, err := core.Init("Your application/1.0", "Config.yaml", nil)
|
||||
if status != core.ExitSuccess {
|
||||
fmt.Printf("Error %d initializing backend: %s\n", status, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
core.InitLog()
|
||||
core.Init("Your application/1.0")
|
||||
}
|
||||
backend.Connect()
|
||||
|
||||
func main() {
|
||||
core.Connect()
|
||||
|
||||
// use functions from core package, for example to find and download files
|
||||
// Use the backend functions for example to search for files or download them.
|
||||
// The webapi package exports some high-level functions that can be used directly (without calling the HTTP API).
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ func (peer *PeerInfo) startBlockTransfer(BlockchainPublicKey *btcec.PublicKey, L
|
||||
|
||||
// register the sequence since packets are sent bi-directional
|
||||
virtualConn.sequenceNumber = sequenceNumber
|
||||
networks.Sequences.RegisterSequenceBi(peer.PublicKey, sequenceNumber, virtualConn, blockSequenceTimeout, virtualConn.sequenceTerminate)
|
||||
peer.Backend.networks.Sequences.RegisterSequenceBi(peer.PublicKey, sequenceNumber, virtualConn, blockSequenceTimeout, virtualConn.sequenceTerminate)
|
||||
|
||||
udtConfig := udt.DefaultConfig()
|
||||
udtConfig.MaxPacketSize = protocol.TransferMaxEmbedSize
|
||||
@@ -48,7 +48,7 @@ func (peer *PeerInfo) startBlockTransfer(BlockchainPublicKey *btcec.PublicKey, L
|
||||
|
||||
for _, target := range TargetBlocks {
|
||||
for blockN := target.Offset; blockN < target.Offset+target.Limit; blockN++ {
|
||||
blockData, status, err := UserBlockchain.GetBlockRaw(blockN)
|
||||
blockData, status, err := peer.Backend.UserBlockchain.GetBlockRaw(blockN)
|
||||
if err != nil {
|
||||
protocol.BlockTransferWriteHeader(udtConn, protocol.GetBlockStatusNotAvailable, protocol.BlockRange{Offset: blockN, Limit: 1}, 0)
|
||||
continue
|
||||
@@ -84,7 +84,7 @@ func (peer *PeerInfo) BlockTransferRequest(BlockchainPublicKey *btcec.PublicKey,
|
||||
})
|
||||
|
||||
// new sequence
|
||||
sequence := networks.Sequences.NewSequenceBi(peer.PublicKey, &peer.messageSequence, virtualConn, blockSequenceTimeout, virtualConn.sequenceTerminate)
|
||||
sequence := peer.Backend.networks.Sequences.NewSequenceBi(peer.PublicKey, &peer.messageSequence, virtualConn, blockSequenceTimeout, virtualConn.sequenceTerminate)
|
||||
if sequence == nil {
|
||||
return nil, nil, errors.New("cannot acquire sequence")
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func (peer *PeerInfo) startFileTransferUDT(hash []byte, fileSize uint64, offset,
|
||||
|
||||
// register the sequence since packets are sent bi-directional
|
||||
virtualConnection.sequenceNumber = sequenceNumber
|
||||
networks.Sequences.RegisterSequenceBi(peer.PublicKey, sequenceNumber, virtualConnection, transferSequenceTimeout, virtualConnection.sequenceTerminate)
|
||||
peer.Backend.networks.Sequences.RegisterSequenceBi(peer.PublicKey, sequenceNumber, virtualConnection, transferSequenceTimeout, virtualConnection.sequenceTerminate)
|
||||
|
||||
udtConfig := udt.DefaultConfig()
|
||||
udtConfig.MaxPacketSize = protocol.TransferMaxEmbedSize
|
||||
@@ -60,7 +60,7 @@ func (peer *PeerInfo) startFileTransferUDT(hash []byte, fileSize uint64, offset,
|
||||
// First send the header (Total File Size, Transfer Size) and then the file data.
|
||||
protocol.FileTransferWriteHeader(udtConn, fileSize, limit)
|
||||
|
||||
_, _, err = UserWarehouse.ReadFile(hash, int64(offset), int64(limit), udtConn)
|
||||
_, _, err = peer.Backend.UserWarehouse.ReadFile(hash, int64(offset), int64(limit), udtConn)
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func (peer *PeerInfo) FileTransferRequestUDT(hash []byte, offset, limit uint64)
|
||||
})
|
||||
|
||||
// new sequence
|
||||
sequence := networks.Sequences.NewSequenceBi(peer.PublicKey, &peer.messageSequence, virtualConn, transferSequenceTimeout, virtualConn.sequenceTerminate)
|
||||
sequence := peer.Backend.networks.Sequences.NewSequenceBi(peer.PublicKey, &peer.messageSequence, virtualConn, transferSequenceTimeout, virtualConn.sequenceTerminate)
|
||||
if sequence == nil {
|
||||
return nil, nil, errors.New("cannot acquire sequence")
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func (v *virtualPacketConn) sequenceTerminate() {
|
||||
// Do not call the function manually; otherwise the underlying transfer protocol may not have time to send a termination message (and the remote peer would subsequently try to reconnect).
|
||||
// Rather, use the underlying transfer protocol's close function.
|
||||
func (v *virtualPacketConn) Close(reason int) (err error) {
|
||||
networks.Sequences.InvalidateSequence(v.peer.PublicKey, v.sequenceNumber, true)
|
||||
v.peer.Backend.networks.Sequences.InvalidateSequence(v.peer.PublicKey, v.sequenceNumber, true)
|
||||
return v.Terminate(reason)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,14 +10,11 @@ import (
|
||||
"github.com/PeernetOfficial/core/warehouse"
|
||||
)
|
||||
|
||||
// UserWarehouse is the user's warehouse for storing files that are shared
|
||||
var UserWarehouse *warehouse.Warehouse
|
||||
|
||||
func initUserWarehouse() {
|
||||
func (backend *Backend) initUserWarehouse() {
|
||||
var err error
|
||||
UserWarehouse, err = warehouse.Init(config.WarehouseMain)
|
||||
backend.UserWarehouse, err = warehouse.Init(backend.Config.WarehouseMain)
|
||||
|
||||
if err != nil {
|
||||
Filters.LogError("initUserWarehouse", "error: %s\n", err.Error())
|
||||
backend.Filters.LogError("initUserWarehouse", "error: %s\n", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,40 +58,40 @@ func Start(Backend *core.Backend, ListenAddresses []string, UseSSL bool, Certifi
|
||||
}
|
||||
|
||||
api.Router.HandleFunc("/test", apiTest).Methods("GET")
|
||||
api.Router.HandleFunc("/status", apiStatus).Methods("GET")
|
||||
api.Router.HandleFunc("/account/info", apiAccountInfo).Methods("GET")
|
||||
api.Router.HandleFunc("/account/delete", apiAccountDelete).Methods("GET")
|
||||
api.Router.HandleFunc("/blockchain/header", apiBlockchainHeaderFunc).Methods("GET")
|
||||
api.Router.HandleFunc("/blockchain/append", apiBlockchainAppend).Methods("POST")
|
||||
api.Router.HandleFunc("/blockchain/read", apiBlockchainRead).Methods("GET")
|
||||
api.Router.HandleFunc("/blockchain/file/add", apiBlockchainFileAdd).Methods("POST")
|
||||
api.Router.HandleFunc("/blockchain/file/list", apiBlockchainFileList).Methods("GET")
|
||||
api.Router.HandleFunc("/blockchain/file/delete", apiBlockchainFileDelete).Methods("POST")
|
||||
api.Router.HandleFunc("/blockchain/file/update", apiBlockchainFileUpdate).Methods("POST")
|
||||
api.Router.HandleFunc("/profile/list", apiProfileList).Methods("GET")
|
||||
api.Router.HandleFunc("/profile/read", apiProfileRead).Methods("GET")
|
||||
api.Router.HandleFunc("/profile/write", apiProfileWrite).Methods("POST")
|
||||
api.Router.HandleFunc("/profile/delete", apiProfileDelete).Methods("POST")
|
||||
api.Router.HandleFunc("/status", api.apiStatus).Methods("GET")
|
||||
api.Router.HandleFunc("/account/info", api.apiAccountInfo).Methods("GET")
|
||||
api.Router.HandleFunc("/account/delete", api.apiAccountDelete).Methods("GET")
|
||||
api.Router.HandleFunc("/blockchain/header", api.apiBlockchainHeaderFunc).Methods("GET")
|
||||
api.Router.HandleFunc("/blockchain/append", api.apiBlockchainAppend).Methods("POST")
|
||||
api.Router.HandleFunc("/blockchain/read", api.apiBlockchainRead).Methods("GET")
|
||||
api.Router.HandleFunc("/blockchain/file/add", api.apiBlockchainFileAdd).Methods("POST")
|
||||
api.Router.HandleFunc("/blockchain/file/list", api.apiBlockchainFileList).Methods("GET")
|
||||
api.Router.HandleFunc("/blockchain/file/delete", api.apiBlockchainFileDelete).Methods("POST")
|
||||
api.Router.HandleFunc("/blockchain/file/update", api.apiBlockchainFileUpdate).Methods("POST")
|
||||
api.Router.HandleFunc("/profile/list", api.apiProfileList).Methods("GET")
|
||||
api.Router.HandleFunc("/profile/read", api.apiProfileRead).Methods("GET")
|
||||
api.Router.HandleFunc("/profile/write", api.apiProfileWrite).Methods("POST")
|
||||
api.Router.HandleFunc("/profile/delete", api.apiProfileDelete).Methods("POST")
|
||||
api.Router.HandleFunc("/search", api.apiSearch).Methods("POST")
|
||||
api.Router.HandleFunc("/search/result", apiSearchResult).Methods("GET")
|
||||
api.Router.HandleFunc("/search/result/ws", apiSearchResultStream).Methods("GET")
|
||||
api.Router.HandleFunc("/search/statistic", apiSearchStatistic).Methods("GET")
|
||||
api.Router.HandleFunc("/search/terminate", apiSearchTerminate).Methods("GET")
|
||||
api.Router.HandleFunc("/search/result", api.apiSearchResult).Methods("GET")
|
||||
api.Router.HandleFunc("/search/result/ws", api.apiSearchResultStream).Methods("GET")
|
||||
api.Router.HandleFunc("/search/statistic", api.apiSearchStatistic).Methods("GET")
|
||||
api.Router.HandleFunc("/search/terminate", api.apiSearchTerminate).Methods("GET")
|
||||
api.Router.HandleFunc("/explore", api.apiExplore).Methods("GET")
|
||||
api.Router.HandleFunc("/file/format", apiFileFormat).Methods("GET")
|
||||
api.Router.HandleFunc("/download/start", apiDownloadStart).Methods("GET")
|
||||
api.Router.HandleFunc("/download/status", apiDownloadStatus).Methods("GET")
|
||||
api.Router.HandleFunc("/download/action", apiDownloadAction).Methods("GET")
|
||||
api.Router.HandleFunc("/warehouse/create", apiWarehouseCreateFile).Methods("POST")
|
||||
api.Router.HandleFunc("/warehouse/create/path", apiWarehouseCreateFilePath).Methods("GET")
|
||||
api.Router.HandleFunc("/warehouse/read", apiWarehouseReadFile).Methods("GET")
|
||||
api.Router.HandleFunc("/warehouse/read/path", apiWarehouseReadFilePath).Methods("GET")
|
||||
api.Router.HandleFunc("/warehouse/delete", apiWarehouseDeleteFile).Methods("GET")
|
||||
api.Router.HandleFunc("/file/read", apiFileRead).Methods("GET")
|
||||
api.Router.HandleFunc("/file/view", apiFileView).Methods("GET")
|
||||
api.Router.HandleFunc("/file/format", api.apiFileFormat).Methods("GET")
|
||||
api.Router.HandleFunc("/download/start", api.apiDownloadStart).Methods("GET")
|
||||
api.Router.HandleFunc("/download/status", api.apiDownloadStatus).Methods("GET")
|
||||
api.Router.HandleFunc("/download/action", api.apiDownloadAction).Methods("GET")
|
||||
api.Router.HandleFunc("/warehouse/create", api.apiWarehouseCreateFile).Methods("POST")
|
||||
api.Router.HandleFunc("/warehouse/create/path", api.apiWarehouseCreateFilePath).Methods("GET")
|
||||
api.Router.HandleFunc("/warehouse/read", api.apiWarehouseReadFile).Methods("GET")
|
||||
api.Router.HandleFunc("/warehouse/read/path", api.apiWarehouseReadFilePath).Methods("GET")
|
||||
api.Router.HandleFunc("/warehouse/delete", api.apiWarehouseDeleteFile).Methods("GET")
|
||||
api.Router.HandleFunc("/file/read", api.apiFileRead).Methods("GET")
|
||||
api.Router.HandleFunc("/file/view", api.apiFileView).Methods("GET")
|
||||
|
||||
for _, listen := range ListenAddresses {
|
||||
go startWebAPI(listen, UseSSL, CertificateFile, CertificateKey, api.Router, "API", TimeoutRead, TimeoutWrite)
|
||||
go startWebAPI(Backend, listen, UseSSL, CertificateFile, CertificateKey, api.Router, "API", TimeoutRead, TimeoutWrite)
|
||||
}
|
||||
|
||||
return api
|
||||
@@ -99,8 +99,8 @@ func Start(Backend *core.Backend, ListenAddresses []string, UseSSL bool, Certifi
|
||||
|
||||
// startWebAPI starts a web-server with given parameters and logs the status. If may block forever and only returns if there is an error.
|
||||
// The certificate file and key are only used if SSL is enabled. The read and write timeout may be 0 for no timeout.
|
||||
func startWebAPI(WebListen string, UseSSL bool, CertificateFile, CertificateKey string, Handler http.Handler, Info string, ReadTimeout, WriteTimeout time.Duration) {
|
||||
core.Filters.LogError("startWebAPI", "Start API at '%s'\n", WebListen)
|
||||
func startWebAPI(Backend *core.Backend, WebListen string, UseSSL bool, CertificateFile, CertificateKey string, Handler http.Handler, Info string, ReadTimeout, WriteTimeout time.Duration) {
|
||||
Backend.Filters.LogError("startWebAPI", "Start API at '%s'\n", WebListen)
|
||||
|
||||
tlsConfig := &tls.Config{MinVersion: tls.VersionTLS12} // for security reasons disable TLS 1.0/1.1
|
||||
|
||||
@@ -116,23 +116,23 @@ func startWebAPI(WebListen string, UseSSL bool, CertificateFile, CertificateKey
|
||||
if UseSSL {
|
||||
// HTTPS
|
||||
if err := server.ListenAndServeTLS(CertificateFile, CertificateKey); err != nil {
|
||||
core.Filters.LogError("startWebAPI", "Error listening on '%s': %v\n", WebListen, err)
|
||||
Backend.Filters.LogError("startWebAPI", "Error listening on '%s': %v\n", WebListen, err)
|
||||
}
|
||||
} else {
|
||||
// HTTP
|
||||
if err := server.ListenAndServe(); err != nil {
|
||||
core.Filters.LogError("startWebAPI", "Error listening on '%s': %v\n", WebListen, err)
|
||||
Backend.Filters.LogError("startWebAPI", "Error listening on '%s': %v\n", WebListen, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EncodeJSON encodes the data as JSON
|
||||
func EncodeJSON(w http.ResponseWriter, r *http.Request, data interface{}) (err error) {
|
||||
func EncodeJSON(Backend *core.Backend, w http.ResponseWriter, r *http.Request, data interface{}) (err error) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
err = json.NewEncoder(w).Encode(data)
|
||||
if err != nil {
|
||||
core.Filters.LogError("EncodeJSON", "Error writing data for route '%s': %v\n", r.URL.Path, err)
|
||||
Backend.Filters.LogError("EncodeJSON", "Error writing data for route '%s': %v\n", r.URL.Path, err)
|
||||
}
|
||||
|
||||
return err
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/PeernetOfficial/core"
|
||||
"github.com/PeernetOfficial/core/blockchain"
|
||||
)
|
||||
|
||||
@@ -27,10 +26,10 @@ apiBlockchainHeaderFunc returns the current blockchain header information
|
||||
Request: GET /blockchain/header
|
||||
Result: 200 with JSON structure apiResponsePeerSelf
|
||||
*/
|
||||
func apiBlockchainHeaderFunc(w http.ResponseWriter, r *http.Request) {
|
||||
publicKey, height, version := core.UserBlockchain.Header()
|
||||
func (api *WebapiInstance) apiBlockchainHeaderFunc(w http.ResponseWriter, r *http.Request) {
|
||||
publicKey, height, version := api.backend.UserBlockchain.Header()
|
||||
|
||||
EncodeJSON(w, r, apiBlockchainHeader{Version: version, Height: height, PeerID: hex.EncodeToString(publicKey.SerializeCompressed())})
|
||||
EncodeJSON(api.backend, w, r, apiBlockchainHeader{Version: version, Height: height, PeerID: hex.EncodeToString(publicKey.SerializeCompressed())})
|
||||
}
|
||||
|
||||
type apiBlockRecordRaw struct {
|
||||
@@ -56,7 +55,7 @@ Do not use this function. Adding invalid data to the blockchain may corrupt it w
|
||||
Request: POST /blockchain/append with JSON structure apiBlockchainBlockRaw
|
||||
Response: 200 with JSON structure apiBlockchainBlockStatus
|
||||
*/
|
||||
func apiBlockchainAppend(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiBlockchainAppend(w http.ResponseWriter, r *http.Request) {
|
||||
var input apiBlockchainBlockRaw
|
||||
if err := DecodeJSON(w, r, &input); err != nil {
|
||||
return
|
||||
@@ -68,9 +67,9 @@ func apiBlockchainAppend(w http.ResponseWriter, r *http.Request) {
|
||||
records = append(records, blockchain.BlockRecordRaw{Type: record.Type, Data: record.Data})
|
||||
}
|
||||
|
||||
newHeight, newVersion, status := core.UserBlockchain.Append(records)
|
||||
newHeight, newVersion, status := api.backend.UserBlockchain.Append(records)
|
||||
|
||||
EncodeJSON(w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
}
|
||||
|
||||
type apiBlockchainBlock struct {
|
||||
@@ -89,7 +88,7 @@ apiBlockchainRead reads a block and returns the decoded information.
|
||||
Request: GET /blockchain/read?block=[number]
|
||||
Result: 200 with JSON structure apiBlockchainBlock
|
||||
*/
|
||||
func apiBlockchainRead(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiBlockchainRead(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
blockN, err := strconv.Atoi(r.Form.Get("block"))
|
||||
if err != nil || blockN < 0 {
|
||||
@@ -97,7 +96,7 @@ func apiBlockchainRead(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
block, status, _ := core.UserBlockchain.Read(uint64(blockN))
|
||||
block, status, _ := api.backend.UserBlockchain.Read(uint64(blockN))
|
||||
result := apiBlockchainBlock{Status: status}
|
||||
|
||||
if status == 0 {
|
||||
@@ -119,5 +118,5 @@ func apiBlockchainRead(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, result)
|
||||
EncodeJSON(api.backend, w, r, result)
|
||||
}
|
||||
|
||||
@@ -13,20 +13,19 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core"
|
||||
"github.com/PeernetOfficial/core/warehouse"
|
||||
)
|
||||
|
||||
// Starts the download.
|
||||
func (info *downloadInfo) Start() {
|
||||
// current user?
|
||||
if bytes.Equal(info.nodeID, core.SelfNodeID()) {
|
||||
if bytes.Equal(info.nodeID, info.backend.SelfNodeID()) {
|
||||
info.DownloadSelf()
|
||||
return
|
||||
}
|
||||
|
||||
for n := 0; n < 3 && info.peer == nil; n++ {
|
||||
_, info.peer, _ = core.FindNode(info.nodeID, time.Second*5)
|
||||
_, info.peer, _ = info.backend.FindNode(info.nodeID, time.Second*5)
|
||||
|
||||
if info.status == DownloadCanceled {
|
||||
return
|
||||
@@ -179,7 +178,7 @@ func (info *downloadInfo) storeDownloadData(data []byte, offset uint64) (status
|
||||
|
||||
func (info *downloadInfo) DownloadSelf() {
|
||||
// Check if the file is available in the local warehouse.
|
||||
_, fileInfo, status, _ := core.UserWarehouse.FileExists(info.hash)
|
||||
_, fileInfo, status, _ := info.backend.UserWarehouse.FileExists(info.hash)
|
||||
if status != warehouse.StatusOK {
|
||||
info.status = DownloadCanceled
|
||||
return
|
||||
@@ -189,7 +188,7 @@ func (info *downloadInfo) DownloadSelf() {
|
||||
info.status = DownloadActive
|
||||
|
||||
// read the file
|
||||
status, bytesRead, _ := core.UserWarehouse.ReadFile(info.hash, 0, int64(fileInfo.Size()), info.DiskFile.Handle)
|
||||
status, bytesRead, _ := info.backend.UserWarehouse.ReadFile(info.hash, 0, int64(fileInfo.Size()), info.DiskFile.Handle)
|
||||
|
||||
info.DiskFile.StoredSize = uint64(bytesRead)
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ The hash parameter identifies the file to download. The node ID identifies the b
|
||||
Request: GET /download/start?path=[target path on disk]&hash=[file hash to download]&node=[node ID]
|
||||
Result: 200 with JSON structure apiResponseDownloadStatus
|
||||
*/
|
||||
func apiDownloadStart(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiDownloadStart(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
|
||||
// validate hashes, must be blake3
|
||||
@@ -76,11 +76,11 @@ func apiDownloadStart(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
info := &downloadInfo{id: uuid.New(), created: time.Now(), hash: hash, nodeID: nodeID}
|
||||
info := &downloadInfo{backend: api.backend, id: uuid.New(), created: time.Now(), hash: hash, nodeID: nodeID}
|
||||
|
||||
// create the file immediately
|
||||
if info.initDiskFile(filePath) != nil {
|
||||
EncodeJSON(w, r, apiResponseDownloadStatus{APIStatus: DownloadResponseFileInvalid})
|
||||
EncodeJSON(api.backend, w, r, apiResponseDownloadStatus{APIStatus: DownloadResponseFileInvalid})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ func apiDownloadStart(w http.ResponseWriter, r *http.Request) {
|
||||
// start the download!
|
||||
go info.Start()
|
||||
|
||||
EncodeJSON(w, r, apiResponseDownloadStatus{APIStatus: DownloadResponseSuccess, ID: info.id, DownloadStatus: DownloadWaitMetadata})
|
||||
EncodeJSON(api.backend, w, r, apiResponseDownloadStatus{APIStatus: DownloadResponseSuccess, ID: info.id, DownloadStatus: DownloadWaitMetadata})
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -99,7 +99,7 @@ apiDownloadStatus returns the status of an active download.
|
||||
Request: GET /download/status?id=[download ID]
|
||||
Result: 200 with JSON structure apiResponseDownloadStatus
|
||||
*/
|
||||
func apiDownloadStatus(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiDownloadStatus(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
id, err := uuid.Parse(r.Form.Get("id"))
|
||||
if err != nil {
|
||||
@@ -109,7 +109,7 @@ func apiDownloadStatus(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
info := downloadLookup(id)
|
||||
if info == nil {
|
||||
EncodeJSON(w, r, apiResponseDownloadStatus{APIStatus: DownloadResponseIDNotFound})
|
||||
EncodeJSON(api.backend, w, r, apiResponseDownloadStatus{APIStatus: DownloadResponseIDNotFound})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ func apiDownloadStatus(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
info.RUnlock()
|
||||
|
||||
EncodeJSON(w, r, response)
|
||||
EncodeJSON(api.backend, w, r, response)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -143,7 +143,7 @@ Action: 0 = Pause, 1 = Resume, 2 = Cancel.
|
||||
Request: GET /download/action?id=[download ID]&action=[action]
|
||||
Result: 200 with JSON structure apiResponseDownloadStatus (using APIStatus and DownloadStatus)
|
||||
*/
|
||||
func apiDownloadAction(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiDownloadAction(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
id, err := uuid.Parse(r.Form.Get("id"))
|
||||
action, err2 := strconv.Atoi(r.Form.Get("action"))
|
||||
@@ -154,7 +154,7 @@ func apiDownloadAction(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
info := downloadLookup(id)
|
||||
if info == nil {
|
||||
EncodeJSON(w, r, apiResponseDownloadStatus{APIStatus: DownloadResponseIDNotFound})
|
||||
EncodeJSON(api.backend, w, r, apiResponseDownloadStatus{APIStatus: DownloadResponseIDNotFound})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ func apiDownloadAction(w http.ResponseWriter, r *http.Request) {
|
||||
apiStatus = info.Cancel()
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, apiResponseDownloadStatus{APIStatus: apiStatus, ID: info.id, DownloadStatus: info.status})
|
||||
EncodeJSON(api.backend, w, r, apiResponseDownloadStatus{APIStatus: apiStatus, ID: info.id, DownloadStatus: info.status})
|
||||
}
|
||||
|
||||
// ---- download tracking ----
|
||||
@@ -203,6 +203,8 @@ type downloadInfo struct {
|
||||
|
||||
// live connections, to be changed
|
||||
peer *core.PeerInfo
|
||||
|
||||
backend *core.Backend
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -203,7 +203,7 @@ It will primarily use the file extension for detection. If unavailable, it uses
|
||||
Request: GET /file/format?path=[file path on disk]
|
||||
Result: 200 with JSON structure apiResponseFileFormat
|
||||
*/
|
||||
func apiFileFormat(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiFileFormat(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
filePath := r.Form.Get("path")
|
||||
if filePath == "" {
|
||||
@@ -213,9 +213,9 @@ func apiFileFormat(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
fileType, fileFormat, err := FileDetectType(filePath)
|
||||
if err != nil {
|
||||
EncodeJSON(w, r, apiResponseFileFormat{Status: 1})
|
||||
EncodeJSON(api.backend, w, r, apiResponseFileFormat{Status: 1})
|
||||
return
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, apiResponseFileFormat{Status: 0, FileType: fileType, FileFormat: fileFormat})
|
||||
EncodeJSON(api.backend, w, r, apiResponseFileFormat{Status: 0, FileType: fileType, FileFormat: fileFormat})
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ Response: 200 with the content
|
||||
404 if the file was not found or other error on transfer initiate
|
||||
502 if unable to find or connect to the remote peer in time
|
||||
*/
|
||||
func apiFileRead(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiFileRead(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
var err error
|
||||
|
||||
@@ -69,7 +69,7 @@ func apiFileRead(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Is the file available in the local warehouse? In that case requesting it from the remote is unnecessary.
|
||||
if serveFileFromWarehouse(w, fileHash, uint64(offset), uint64(limit), ranges) {
|
||||
if serveFileFromWarehouse(api.backend, w, fileHash, uint64(offset), uint64(limit), ranges) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -77,9 +77,9 @@ func apiFileRead(w http.ResponseWriter, r *http.Request) {
|
||||
var peer *core.PeerInfo
|
||||
|
||||
if valid2 {
|
||||
peer, err = PeerConnectNode(nodeID, timeout)
|
||||
peer, err = PeerConnectNode(api.backend, nodeID, timeout)
|
||||
} else if err3 == nil {
|
||||
peer, err = PeerConnectPublicKey(publicKey, timeout)
|
||||
peer, err = PeerConnectPublicKey(api.backend, publicKey, timeout)
|
||||
}
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadGateway)
|
||||
@@ -105,9 +105,9 @@ func apiFileRead(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// serveFileFromWarehouse serves the file from the warehouse. If it is not available, it returns false and does not use the writer.
|
||||
// Limit is optional, 0 means the entire file.
|
||||
func serveFileFromWarehouse(w http.ResponseWriter, fileHash []byte, offset, limit uint64, ranges []HTTPRange) (valid bool) {
|
||||
func serveFileFromWarehouse(backend *core.Backend, w http.ResponseWriter, fileHash []byte, offset, limit uint64, ranges []HTTPRange) (valid bool) {
|
||||
// Check if the file is available in the local warehouse.
|
||||
_, fileInfo, status, _ := core.UserWarehouse.FileExists(fileHash)
|
||||
_, fileInfo, status, _ := backend.UserWarehouse.FileExists(fileHash)
|
||||
if status != warehouse.StatusOK {
|
||||
return false
|
||||
}
|
||||
@@ -126,7 +126,7 @@ func serveFileFromWarehouse(w http.ResponseWriter, fileHash []byte, offset, limi
|
||||
|
||||
setContentLengthRangeHeader(w, offset, limit, uint64(fileInfo.Size()), ranges)
|
||||
|
||||
status, _, _ = core.UserWarehouse.ReadFile(fileHash, int64(offset), int64(limit), w)
|
||||
status, _, _ = backend.UserWarehouse.ReadFile(fileHash, int64(offset), int64(limit), w)
|
||||
|
||||
// StatusErrorReadFile must be considered success, since parts of the file may have been transferred already and recovery is not possible.
|
||||
return status == warehouse.StatusErrorReadFile || status == warehouse.StatusOK
|
||||
@@ -148,7 +148,7 @@ Response: 200 with the content
|
||||
404 if the file was not found or other error on transfer initiate
|
||||
502 if unable to find or connect to the remote peer in time
|
||||
*/
|
||||
func apiFileView(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiFileView(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
var err error
|
||||
|
||||
@@ -194,7 +194,7 @@ func apiFileView(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Is the file available in the local warehouse? In that case requesting it from the remote is unnecessary.
|
||||
if !localCacheDisable {
|
||||
if serveFileFromWarehouse(w, fileHash, uint64(offset), uint64(limit), ranges) {
|
||||
if serveFileFromWarehouse(api.backend, w, fileHash, uint64(offset), uint64(limit), ranges) {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -203,9 +203,9 @@ func apiFileView(w http.ResponseWriter, r *http.Request) {
|
||||
var peer *core.PeerInfo
|
||||
|
||||
if valid2 {
|
||||
peer, err = PeerConnectNode(nodeID, timeout)
|
||||
peer, err = PeerConnectNode(api.backend, nodeID, timeout)
|
||||
} else if err3 == nil {
|
||||
peer, err = PeerConnectPublicKey(publicKey, timeout)
|
||||
peer, err = PeerConnectPublicKey(api.backend, publicKey, timeout)
|
||||
}
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadGateway)
|
||||
@@ -230,19 +230,19 @@ func apiFileView(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// PeerConnectPublicKey attempts to connect to the peer specified by its public key (= peer ID).
|
||||
func PeerConnectPublicKey(publicKey *btcec.PublicKey, timeout time.Duration) (peer *core.PeerInfo, err error) {
|
||||
func PeerConnectPublicKey(backend *core.Backend, publicKey *btcec.PublicKey, timeout time.Duration) (peer *core.PeerInfo, err error) {
|
||||
if publicKey == nil {
|
||||
return nil, errors.New("invalid public key")
|
||||
}
|
||||
|
||||
// First look up in the peer list.
|
||||
if peer = core.PeerlistLookup(publicKey); peer != nil {
|
||||
if peer = backend.PeerlistLookup(publicKey); peer != nil {
|
||||
return peer, nil
|
||||
}
|
||||
|
||||
// Try to connect via DHT.
|
||||
nodeID := protocol.PublicKey2NodeID(publicKey)
|
||||
if _, peer, _ = core.FindNode(nodeID, timeout); peer != nil {
|
||||
if _, peer, _ = backend.FindNode(nodeID, timeout); peer != nil {
|
||||
return peer, nil
|
||||
}
|
||||
|
||||
@@ -251,13 +251,13 @@ func PeerConnectPublicKey(publicKey *btcec.PublicKey, timeout time.Duration) (pe
|
||||
}
|
||||
|
||||
// PeerConnectNode tries to connect via the node ID
|
||||
func PeerConnectNode(nodeID []byte, timeout time.Duration) (peer *core.PeerInfo, err error) {
|
||||
func PeerConnectNode(backend *core.Backend, nodeID []byte, timeout time.Duration) (peer *core.PeerInfo, err error) {
|
||||
if len(nodeID) == 256/8 {
|
||||
return nil, errors.New("invalid node ID")
|
||||
}
|
||||
|
||||
// Try to connect via DHT.
|
||||
if _, peer, _ = core.FindNode(nodeID, timeout); peer != nil {
|
||||
if _, peer, _ = backend.FindNode(nodeID, timeout); peer != nil {
|
||||
return peer, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ Request: POST /blockchain/file/add with JSON structure apiBlockAddFiles
|
||||
Response: 200 with JSON structure apiBlockchainBlockStatus
|
||||
400 if invalid input
|
||||
*/
|
||||
func apiBlockchainFileAdd(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiBlockchainFileAdd(w http.ResponseWriter, r *http.Request) {
|
||||
var input apiBlockAddFiles
|
||||
if err := DecodeJSON(w, r, &input); err != nil {
|
||||
return
|
||||
@@ -154,8 +154,8 @@ func apiBlockchainFileAdd(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := warehouse.ValidateHash(file.Hash); err != nil {
|
||||
http.Error(w, "", http.StatusBadRequest)
|
||||
return
|
||||
} else if _, fileInfo, status, _ := core.UserWarehouse.FileExists(file.Hash); status != warehouse.StatusOK {
|
||||
EncodeJSON(w, r, apiBlockchainBlockStatus{Status: blockchain.StatusNotInWarehouse})
|
||||
} else if _, fileInfo, status, _ := api.backend.UserWarehouse.FileExists(file.Hash); status != warehouse.StatusOK {
|
||||
EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: blockchain.StatusNotInWarehouse})
|
||||
return
|
||||
} else {
|
||||
file.Size = uint64(fileInfo.Size())
|
||||
@@ -168,17 +168,17 @@ func apiBlockchainFileAdd(w http.ResponseWriter, r *http.Request) {
|
||||
blockRecord := blockRecordFileFromAPI(file)
|
||||
|
||||
// Set the merkle tree info as appropriate.
|
||||
if !setFileMerkleInfo(&blockRecord) {
|
||||
EncodeJSON(w, r, apiBlockchainBlockStatus{Status: blockchain.StatusNotInWarehouse})
|
||||
if !setFileMerkleInfo(api.backend, &blockRecord) {
|
||||
EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: blockchain.StatusNotInWarehouse})
|
||||
return
|
||||
}
|
||||
|
||||
filesAdd = append(filesAdd, blockRecord)
|
||||
}
|
||||
|
||||
newHeight, newVersion, status := core.UserBlockchain.AddFiles(filesAdd)
|
||||
newHeight, newVersion, status := api.backend.UserBlockchain.AddFiles(filesAdd)
|
||||
|
||||
EncodeJSON(w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -187,8 +187,8 @@ apiBlockchainFileList lists all files stored on the blockchain.
|
||||
Request: GET /blockchain/file/list
|
||||
Response: 200 with JSON structure apiBlockAddFiles
|
||||
*/
|
||||
func apiBlockchainFileList(w http.ResponseWriter, r *http.Request) {
|
||||
files, status := core.UserBlockchain.ListFiles()
|
||||
func (api *WebapiInstance) apiBlockchainFileList(w http.ResponseWriter, r *http.Request) {
|
||||
files, status := api.backend.UserBlockchain.ListFiles()
|
||||
|
||||
var result apiBlockAddFiles
|
||||
|
||||
@@ -198,7 +198,7 @@ func apiBlockchainFileList(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
result.Status = status
|
||||
|
||||
EncodeJSON(w, r, result)
|
||||
EncodeJSON(api.backend, w, r, result)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -208,7 +208,7 @@ It will automatically delete the file in the Warehouse if there are no other ref
|
||||
Request: POST /blockchain/file/delete with JSON structure apiBlockAddFiles
|
||||
Response: 200 with JSON structure apiBlockchainBlockStatus
|
||||
*/
|
||||
func apiBlockchainFileDelete(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiBlockchainFileDelete(w http.ResponseWriter, r *http.Request) {
|
||||
var input apiBlockAddFiles
|
||||
if err := DecodeJSON(w, r, &input); err != nil {
|
||||
return
|
||||
@@ -220,18 +220,18 @@ func apiBlockchainFileDelete(w http.ResponseWriter, r *http.Request) {
|
||||
deleteIDs = append(deleteIDs, input.Files[n].ID)
|
||||
}
|
||||
|
||||
newHeight, newVersion, deletedFiles, status := core.UserBlockchain.DeleteFiles(deleteIDs)
|
||||
newHeight, newVersion, deletedFiles, status := api.backend.UserBlockchain.DeleteFiles(deleteIDs)
|
||||
|
||||
// If successfully deleted from the blockchain, delete from the Warehouse in case there are no other references.
|
||||
if status == blockchain.StatusOK {
|
||||
for n := range deletedFiles {
|
||||
if files, status := core.UserBlockchain.FileExists(deletedFiles[n].Hash); status == blockchain.StatusOK && len(files) == 0 {
|
||||
core.UserWarehouse.DeleteFile(deletedFiles[n].Hash)
|
||||
if files, status := api.backend.UserBlockchain.FileExists(deletedFiles[n].Hash); status == blockchain.StatusOK && len(files) == 0 {
|
||||
api.backend.UserWarehouse.DeleteFile(deletedFiles[n].Hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -241,7 +241,7 @@ Request: POST /blockchain/file/update with JSON structure apiBlockAddFiles
|
||||
Response: 200 with JSON structure apiBlockchainBlockStatus
|
||||
400 if invalid input
|
||||
*/
|
||||
func apiBlockchainFileUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiBlockchainFileUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
var input apiBlockAddFiles
|
||||
if err := DecodeJSON(w, r, &input); err != nil {
|
||||
return
|
||||
@@ -263,8 +263,8 @@ func apiBlockchainFileUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := warehouse.ValidateHash(file.Hash); err != nil {
|
||||
http.Error(w, "", http.StatusBadRequest)
|
||||
return
|
||||
} else if _, fileInfo, status, _ := core.UserWarehouse.FileExists(file.Hash); status != warehouse.StatusOK {
|
||||
EncodeJSON(w, r, apiBlockchainBlockStatus{Status: blockchain.StatusNotInWarehouse})
|
||||
} else if _, fileInfo, status, _ := api.backend.UserWarehouse.FileExists(file.Hash); status != warehouse.StatusOK {
|
||||
EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: blockchain.StatusNotInWarehouse})
|
||||
return
|
||||
} else {
|
||||
file.Size = uint64(fileInfo.Size())
|
||||
@@ -277,17 +277,17 @@ func apiBlockchainFileUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
blockRecord := blockRecordFileFromAPI(file)
|
||||
|
||||
// Set the merkle tree info as appropriate.
|
||||
if !setFileMerkleInfo(&blockRecord) {
|
||||
EncodeJSON(w, r, apiBlockchainBlockStatus{Status: blockchain.StatusNotInWarehouse})
|
||||
if !setFileMerkleInfo(api.backend, &blockRecord) {
|
||||
EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: blockchain.StatusNotInWarehouse})
|
||||
return
|
||||
}
|
||||
|
||||
filesAdd = append(filesAdd, blockRecord)
|
||||
}
|
||||
|
||||
newHeight, newVersion, status := core.UserBlockchain.ReplaceFiles(filesAdd)
|
||||
newHeight, newVersion, status := api.backend.UserBlockchain.ReplaceFiles(filesAdd)
|
||||
|
||||
EncodeJSON(w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
}
|
||||
|
||||
// ---- metadata functions ----
|
||||
@@ -318,14 +318,14 @@ func (file *apiFile) IsVirtualFolder() bool {
|
||||
}
|
||||
|
||||
// setFileMerkleInfo sets the merkle fields in the BlockRecordFile
|
||||
func setFileMerkleInfo(file *blockchain.BlockRecordFile) (valid bool) {
|
||||
func setFileMerkleInfo(backend *core.Backend, file *blockchain.BlockRecordFile) (valid bool) {
|
||||
if file.Size <= merkle.MinimumFragmentSize {
|
||||
// If smaller or equal than the minimum fragment size, the merkle tree is not used.
|
||||
file.MerkleRootHash = file.Hash
|
||||
file.FragmentSize = merkle.MinimumFragmentSize
|
||||
} else {
|
||||
// Get the information from the Warehouse .merkle companion file.
|
||||
tree, status, _ := core.UserWarehouse.ReadMerkleTree(file.Hash, true)
|
||||
tree, status, _ := backend.UserWarehouse.ReadMerkleTree(file.Hash, true)
|
||||
if status != warehouse.StatusOK {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/PeernetOfficial/core"
|
||||
"github.com/PeernetOfficial/core/blockchain"
|
||||
)
|
||||
|
||||
@@ -35,15 +34,15 @@ apiProfileList lists all users profile fields.
|
||||
Request: GET /profile/list
|
||||
Response: 200 with JSON structure apiProfileData
|
||||
*/
|
||||
func apiProfileList(w http.ResponseWriter, r *http.Request) {
|
||||
fields, status := core.UserBlockchain.ProfileList()
|
||||
func (api *WebapiInstance) apiProfileList(w http.ResponseWriter, r *http.Request) {
|
||||
fields, status := api.backend.UserBlockchain.ProfileList()
|
||||
|
||||
result := apiProfileData{Status: status}
|
||||
for n := range fields {
|
||||
result.Fields = append(result.Fields, blockRecordProfileToAPI(fields[n]))
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, result)
|
||||
EncodeJSON(api.backend, w, r, result)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -52,7 +51,7 @@ apiProfileRead reads a specific users profile field. See core.ProfileX for recog
|
||||
Request: GET /profile/read?field=[index]
|
||||
Response: 200 with JSON structure apiProfileData
|
||||
*/
|
||||
func apiProfileRead(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiProfileRead(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
fieldN, err1 := strconv.Atoi(r.Form.Get("field"))
|
||||
|
||||
@@ -64,11 +63,11 @@ func apiProfileRead(w http.ResponseWriter, r *http.Request) {
|
||||
var result apiProfileData
|
||||
|
||||
var data []byte
|
||||
if data, result.Status = core.UserBlockchain.ProfileReadField(uint16(fieldN)); result.Status == blockchain.StatusOK {
|
||||
if data, result.Status = api.backend.UserBlockchain.ProfileReadField(uint16(fieldN)); result.Status == blockchain.StatusOK {
|
||||
result.Fields = append(result.Fields, blockRecordProfileToAPI(blockchain.BlockRecordProfile{Type: uint16(fieldN), Data: data}))
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, result)
|
||||
EncodeJSON(api.backend, w, r, result)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -77,7 +76,7 @@ apiProfileWrite writes profile fields. See core.ProfileX for recognized fields.
|
||||
Request: POST /profile/write with JSON structure apiProfileData
|
||||
Response: 200 with JSON structure apiBlockchainBlockStatus
|
||||
*/
|
||||
func apiProfileWrite(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiProfileWrite(w http.ResponseWriter, r *http.Request) {
|
||||
var input apiProfileData
|
||||
if err := DecodeJSON(w, r, &input); err != nil {
|
||||
return
|
||||
@@ -89,9 +88,9 @@ func apiProfileWrite(w http.ResponseWriter, r *http.Request) {
|
||||
fields = append(fields, blockRecordProfileFromAPI(input.Fields[n]))
|
||||
}
|
||||
|
||||
newHeight, newVersion, status := core.UserBlockchain.ProfileWrite(fields)
|
||||
newHeight, newVersion, status := api.backend.UserBlockchain.ProfileWrite(fields)
|
||||
|
||||
EncodeJSON(w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -100,7 +99,7 @@ apiProfileDelete deletes profile fields identified by the types. See core.Profil
|
||||
Request: POST /profile/delete with JSON structure apiProfileData
|
||||
Response: 200 with JSON structure apiBlockchainBlockStatus
|
||||
*/
|
||||
func apiProfileDelete(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiProfileDelete(w http.ResponseWriter, r *http.Request) {
|
||||
var input apiProfileData
|
||||
if err := DecodeJSON(w, r, &input); err != nil {
|
||||
return
|
||||
@@ -112,9 +111,9 @@ func apiProfileDelete(w http.ResponseWriter, r *http.Request) {
|
||||
fields = append(fields, input.Fields[n].Type)
|
||||
}
|
||||
|
||||
newHeight, newVersion, status := core.UserBlockchain.ProfileDelete(fields)
|
||||
newHeight, newVersion, status := api.backend.UserBlockchain.ProfileDelete(fields)
|
||||
|
||||
EncodeJSON(w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
}
|
||||
|
||||
// --- conversion from core to API data ---
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core"
|
||||
"github.com/PeernetOfficial/core/blockchain"
|
||||
)
|
||||
|
||||
@@ -20,7 +19,7 @@ func (api *WebapiInstance) dispatchSearch(input SearchRequest) (job *SearchJob)
|
||||
Filter := input.ToSearchFilter()
|
||||
|
||||
// create the search job
|
||||
job = CreateSearchJob(Timeout, input.MaxResults, Filter)
|
||||
job = CreateSearchJob(api.backend, Timeout, input.MaxResults, Filter)
|
||||
|
||||
// todo: create actual search clients!
|
||||
job.Status = SearchStatusLive
|
||||
@@ -56,10 +55,10 @@ resultLoop:
|
||||
}
|
||||
}
|
||||
|
||||
if bytes.Equal(file.NodeID, core.SelfNodeID()) {
|
||||
if bytes.Equal(file.NodeID, job.backend.SelfNodeID()) {
|
||||
// Indicates data from the current user.
|
||||
file.Tags = append(file.Tags, blockchain.TagFromNumber(blockchain.TagSharedByCount, 1))
|
||||
} else if peer := core.NodelistLookup(file.NodeID); peer != nil {
|
||||
} else if peer := job.backend.NodelistLookup(file.NodeID); peer != nil {
|
||||
// add the tags 'Shared By Count' and 'Shared By GeoIP'
|
||||
file.Tags = append(file.Tags, blockchain.TagFromNumber(blockchain.TagSharedByCount, 1))
|
||||
if latitude, longitude, valid := api.Peer2GeoIP(peer); valid {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core"
|
||||
"github.com/PeernetOfficial/core/blockchain"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
@@ -29,6 +30,8 @@ type SearchFilter struct {
|
||||
|
||||
// SearchJob is a collection of search jobs
|
||||
type SearchJob struct {
|
||||
backend *core.Backend
|
||||
|
||||
// input settings
|
||||
id uuid.UUID // The job id
|
||||
timeout time.Duration // timeout set for all searches
|
||||
@@ -79,8 +82,8 @@ const (
|
||||
|
||||
// CreateSearchJob creates a new search job and adds it to the lookup list.
|
||||
// Timeout and MaxResults must be set and must not be 0.
|
||||
func CreateSearchJob(Timeout time.Duration, MaxResults int, Filter SearchFilter) (job *SearchJob) {
|
||||
job = &SearchJob{}
|
||||
func CreateSearchJob(Backend *core.Backend, Timeout time.Duration, MaxResults int, Filter SearchFilter) (job *SearchJob) {
|
||||
job = &SearchJob{backend: Backend}
|
||||
job.Status = SearchStatusNotStarted
|
||||
job.id = uuid.New()
|
||||
job.timeout = Timeout
|
||||
|
||||
@@ -106,7 +106,7 @@ func (api *WebapiInstance) apiSearch(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
job := api.dispatchSearch(input)
|
||||
|
||||
EncodeJSON(w, r, SearchRequestResponse{Status: 0, ID: job.id})
|
||||
EncodeJSON(api.backend, w, r, SearchRequestResponse{Status: 0, ID: job.id})
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -124,7 +124,7 @@ Optional parameters:
|
||||
&sort=[sort order]
|
||||
Result: 200 with JSON structure SearchResult. Check the field status.
|
||||
*/
|
||||
func apiSearchResult(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiSearchResult(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
jobID, err := uuid.Parse(r.Form.Get("id"))
|
||||
if err != nil {
|
||||
@@ -139,7 +139,7 @@ func apiSearchResult(w http.ResponseWriter, r *http.Request) {
|
||||
// find the job ID
|
||||
job := JobLookup(jobID)
|
||||
if job == nil {
|
||||
EncodeJSON(w, r, SearchResult{Status: 2})
|
||||
EncodeJSON(api.backend, w, r, SearchResult{Status: 2})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ func apiSearchResult(w http.ResponseWriter, r *http.Request) {
|
||||
result.Statistic = job.Statistics()
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, result)
|
||||
EncodeJSON(api.backend, w, r, result)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -204,7 +204,7 @@ Request: GET /search/result/ws?id=[UUID]&limit=[optional max records]
|
||||
Result: If successful, upgrades to a websocket and sends JSON structure SearchResult messages.
|
||||
Limit is optional. Not used if ommitted or 0.
|
||||
*/
|
||||
func apiSearchResultStream(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiSearchResultStream(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
jobID, err := uuid.Parse(r.Form.Get("id"))
|
||||
if err != nil {
|
||||
@@ -217,7 +217,7 @@ func apiSearchResultStream(w http.ResponseWriter, r *http.Request) {
|
||||
// look up the job
|
||||
job := JobLookup(jobID)
|
||||
if job == nil {
|
||||
EncodeJSON(w, r, SearchResult{Status: 2})
|
||||
EncodeJSON(api.backend, w, r, SearchResult{Status: 2})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ Response: 204 Empty
|
||||
400 Invalid input
|
||||
404 ID not found
|
||||
*/
|
||||
func apiSearchTerminate(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiSearchTerminate(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
r.ParseForm()
|
||||
jobID, err := uuid.Parse(r.Form.Get("id"))
|
||||
@@ -318,7 +318,7 @@ apiSearchStatistic returns search result statistics. Statistics are always calcu
|
||||
Request: GET /search/result?id=[UUID]
|
||||
Result: 200 with JSON structure SearchStatistic. Check the field status (0 = Success, 2 = ID not found).
|
||||
*/
|
||||
func apiSearchStatistic(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiSearchStatistic(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
jobID, err := uuid.Parse(r.Form.Get("id"))
|
||||
if err != nil {
|
||||
@@ -329,13 +329,13 @@ func apiSearchStatistic(w http.ResponseWriter, r *http.Request) {
|
||||
// find the job ID
|
||||
job := JobLookup(jobID)
|
||||
if job == nil {
|
||||
EncodeJSON(w, r, SearchStatistic{Status: 2})
|
||||
EncodeJSON(api.backend, w, r, SearchStatistic{Status: 2})
|
||||
return
|
||||
}
|
||||
|
||||
stats := job.Statistics()
|
||||
|
||||
EncodeJSON(w, r, SearchStatistic{SearchStatisticData: stats, Status: 0, IsTerminated: job.IsTerminated()})
|
||||
EncodeJSON(api.backend, w, r, SearchStatistic{SearchStatisticData: stats, Status: 0, IsTerminated: job.IsTerminated()})
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -372,7 +372,7 @@ func (api *WebapiInstance) apiExplore(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
result.Status = 1 // No more results to expect
|
||||
|
||||
EncodeJSON(w, r, result)
|
||||
EncodeJSON(api.backend, w, r, result)
|
||||
}
|
||||
|
||||
func (input *SearchRequest) Parse() (Timeout time.Duration) {
|
||||
|
||||
@@ -19,7 +19,7 @@ func (api *WebapiInstance) queryRecentShared(backend *core.Backend, fileType int
|
||||
}
|
||||
|
||||
// Use the peer list to know about active peers. Random order!
|
||||
peerList := core.PeerlistGet()
|
||||
peerList := api.backend.PeerlistGet()
|
||||
|
||||
// Files from peers exceeding the limit. It is used if from all peers the total limit is not reached.
|
||||
var filesSeconday []blockchain.BlockRecordFile
|
||||
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
"encoding/hex"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/PeernetOfficial/core"
|
||||
)
|
||||
|
||||
func apiTest(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -33,8 +31,8 @@ apiStatus returns the current connectivity status to the network
|
||||
Request: GET /status
|
||||
Result: 200 with JSON structure Status
|
||||
*/
|
||||
func apiStatus(w http.ResponseWriter, r *http.Request) {
|
||||
status := apiResponseStatus{Status: 0, CountPeerList: core.PeerlistCount()}
|
||||
func (api *WebapiInstance) apiStatus(w http.ResponseWriter, r *http.Request) {
|
||||
status := apiResponseStatus{Status: 0, CountPeerList: api.backend.PeerlistCount()}
|
||||
status.CountNetwork = status.CountPeerList // For now always same as CountPeerList, until native Statistics message to root peers is available.
|
||||
|
||||
// Connected: If at leat 2 peers.
|
||||
@@ -42,7 +40,7 @@ func apiStatus(w http.ResponseWriter, r *http.Request) {
|
||||
// Instead, the core should keep a count of "active peers".
|
||||
status.IsConnected = status.CountPeerList >= 2
|
||||
|
||||
EncodeJSON(w, r, status)
|
||||
EncodeJSON(api.backend, w, r, status)
|
||||
}
|
||||
|
||||
type apiResponsePeerSelf struct {
|
||||
@@ -55,14 +53,14 @@ apiAccountInfo provides information about the current account.
|
||||
Request: GET /account/info
|
||||
Result: 200 with JSON structure apiResponsePeerSelf
|
||||
*/
|
||||
func apiAccountInfo(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiAccountInfo(w http.ResponseWriter, r *http.Request) {
|
||||
response := apiResponsePeerSelf{}
|
||||
response.NodeID = hex.EncodeToString(core.SelfNodeID())
|
||||
response.NodeID = hex.EncodeToString(api.backend.SelfNodeID())
|
||||
|
||||
_, publicKey := core.ExportPrivateKey()
|
||||
_, publicKey := api.backend.ExportPrivateKey()
|
||||
response.PeerID = hex.EncodeToString(publicKey.SerializeCompressed())
|
||||
|
||||
EncodeJSON(w, r, response)
|
||||
EncodeJSON(api.backend, w, r, response)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -71,14 +69,14 @@ Request: GET /account/delete?confirm=[0 or 1]
|
||||
Result: 204 if the user choses not to delete the account
|
||||
200 if successfully deleted
|
||||
*/
|
||||
func apiAccountDelete(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiAccountDelete(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
if confirm, _ := strconv.ParseBool(r.Form.Get("confirm")); !confirm {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
core.DeleteAccount()
|
||||
api.backend.DeleteAccount()
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/PeernetOfficial/core"
|
||||
"github.com/PeernetOfficial/core/warehouse"
|
||||
)
|
||||
|
||||
@@ -26,14 +25,14 @@ apiWarehouseCreateFile creates a file in the warehouse.
|
||||
Request: POST /warehouse/create with raw data to create as new file
|
||||
Response: 200 with JSON structure WarehouseResult
|
||||
*/
|
||||
func apiWarehouseCreateFile(w http.ResponseWriter, r *http.Request) {
|
||||
hash, status, err := core.UserWarehouse.CreateFile(r.Body, 0)
|
||||
func (api *WebapiInstance) apiWarehouseCreateFile(w http.ResponseWriter, r *http.Request) {
|
||||
hash, status, err := api.backend.UserWarehouse.CreateFile(r.Body, 0)
|
||||
|
||||
if err != nil {
|
||||
core.Filters.LogError("warehouse.CreateFile", "status %d error: %v", status, err)
|
||||
api.backend.Filters.LogError("warehouse.CreateFile", "status %d error: %v", status, err)
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, WarehouseResult{Status: status, Hash: hash})
|
||||
EncodeJSON(api.backend, w, r, WarehouseResult{Status: status, Hash: hash})
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -44,7 +43,7 @@ In the future the API should be secured using a random API key and setting the C
|
||||
Request: GET /warehouse/create/path?path=[target path on disk]
|
||||
Response: 200 with JSON structure WarehouseResult
|
||||
*/
|
||||
func apiWarehouseCreateFilePath(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiWarehouseCreateFilePath(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
filePath := r.Form.Get("path")
|
||||
if filePath == "" {
|
||||
@@ -52,13 +51,13 @@ func apiWarehouseCreateFilePath(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
hash, status, err := core.UserWarehouse.CreateFileFromPath(filePath)
|
||||
hash, status, err := api.backend.UserWarehouse.CreateFileFromPath(filePath)
|
||||
|
||||
if err != nil {
|
||||
core.Filters.LogError("warehouse.CreateFile", "status %d error: %v", status, err)
|
||||
api.backend.Filters.LogError("warehouse.CreateFile", "status %d error: %v", status, err)
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, WarehouseResult{Status: status, Hash: hash})
|
||||
EncodeJSON(api.backend, w, r, WarehouseResult{Status: status, Hash: hash})
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -70,7 +69,7 @@ Response: 200 with the raw file data
|
||||
404 if file was not found
|
||||
500 in case of internal error opening the file
|
||||
*/
|
||||
func apiWarehouseReadFile(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiWarehouseReadFile(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
hash, valid1 := DecodeBlake3Hash(r.Form.Get("hash"))
|
||||
if !valid1 {
|
||||
@@ -81,7 +80,7 @@ func apiWarehouseReadFile(w http.ResponseWriter, r *http.Request) {
|
||||
offset, _ := strconv.Atoi(r.Form.Get("offset"))
|
||||
limit, _ := strconv.Atoi(r.Form.Get("limit"))
|
||||
|
||||
status, bytesRead, err := core.UserWarehouse.ReadFile(hash, int64(offset), int64(limit), w)
|
||||
status, bytesRead, err := api.backend.UserWarehouse.ReadFile(hash, int64(offset), int64(limit), w)
|
||||
|
||||
switch status {
|
||||
case warehouse.StatusFileNotFound:
|
||||
@@ -95,7 +94,7 @@ func apiWarehouseReadFile(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
core.Filters.LogError("warehouse.ReadFile", "status %d read %d error: %v", status, bytesRead, err)
|
||||
api.backend.Filters.LogError("warehouse.ReadFile", "status %d read %d error: %v", status, bytesRead, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +104,7 @@ apiWarehouseDeleteFile deletes a file in the warehouse.
|
||||
Request: GET /warehouse/delete?hash=[hash]
|
||||
Response: 200 with JSON structure WarehouseResult
|
||||
*/
|
||||
func apiWarehouseDeleteFile(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiWarehouseDeleteFile(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
hash, valid1 := DecodeBlake3Hash(r.Form.Get("hash"))
|
||||
if !valid1 {
|
||||
@@ -113,13 +112,13 @@ func apiWarehouseDeleteFile(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
status, err := core.UserWarehouse.DeleteFile(hash)
|
||||
status, err := api.backend.UserWarehouse.DeleteFile(hash)
|
||||
|
||||
if err != nil {
|
||||
core.Filters.LogError("warehouse.DeleteFile", "status %d error: %v", status, err)
|
||||
api.backend.Filters.LogError("warehouse.DeleteFile", "status %d error: %v", status, err)
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, WarehouseResult{Status: status, Hash: hash})
|
||||
EncodeJSON(api.backend, w, r, WarehouseResult{Status: status, Hash: hash})
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -130,7 +129,7 @@ Request: GET /warehouse/read/path?hash=[hash]&path=[target path on disk]
|
||||
Optional parameters &offset=[file offset]&limit=[read limit in bytes]
|
||||
Response: 200 with JSON structure WarehouseResult
|
||||
*/
|
||||
func apiWarehouseReadFilePath(w http.ResponseWriter, r *http.Request) {
|
||||
func (api *WebapiInstance) apiWarehouseReadFilePath(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
hash, valid1 := DecodeBlake3Hash(r.Form.Get("hash"))
|
||||
if !valid1 {
|
||||
@@ -142,11 +141,11 @@ func apiWarehouseReadFilePath(w http.ResponseWriter, r *http.Request) {
|
||||
offset, _ := strconv.Atoi(r.Form.Get("offset"))
|
||||
limit, _ := strconv.Atoi(r.Form.Get("limit"))
|
||||
|
||||
status, bytesRead, err := core.UserWarehouse.ReadFileToDisk(hash, int64(offset), int64(limit), targetFile)
|
||||
status, bytesRead, err := api.backend.UserWarehouse.ReadFileToDisk(hash, int64(offset), int64(limit), targetFile)
|
||||
|
||||
if err != nil {
|
||||
core.Filters.LogError("warehouse.ReadFileToDisk", "status %d read %d error: %v", status, bytesRead, err)
|
||||
api.backend.Filters.LogError("warehouse.ReadFileToDisk", "status %d read %d error: %v", status, bytesRead, err)
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, WarehouseResult{Status: status, Hash: hash})
|
||||
EncodeJSON(api.backend, w, r, WarehouseResult{Status: status, Hash: hash})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user