github.com/braveheart12/insolar-09-08-19@v0.8.7/network/transport/future.go (about) 1 /* 2 * The Clear BSD License 3 * 4 * Copyright (c) 2019 Insolar Technologies 5 * 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met: 9 * 10 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 11 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 12 * Neither the name of Insolar Technologies nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 13 * 14 * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 * 16 */ 17 18 package transport 19 20 import ( 21 "errors" 22 "sync/atomic" 23 "time" 24 25 "github.com/insolar/insolar/metrics" 26 "github.com/insolar/insolar/network" 27 "github.com/insolar/insolar/network/transport/host" 28 "github.com/insolar/insolar/network/transport/packet" 29 ) 30 31 var ( 32 // ErrTimeout is returned when the operation timeout is exceeded. 33 ErrTimeout = errors.New("timeout") 34 // ErrChannelClosed is returned when the input channel is closed. 35 ErrChannelClosed = errors.New("channel closed") 36 ) 37 38 // Future is network response future. 39 type Future interface { 40 41 // ID returns packet sequence number. 42 ID() network.RequestID 43 44 // Actor returns the initiator of the packet. 45 Actor() *host.Host 46 47 // Request returns origin request. 48 Request() *packet.Packet 49 50 // Result is a channel to listen for future result. 51 Result() <-chan *packet.Packet 52 53 // SetResult makes packet to appear in result channel. 54 SetResult(*packet.Packet) 55 56 // GetResult gets the future result from Result() channel with a timeout set to `duration`. 57 GetResult(duration time.Duration) (*packet.Packet, error) 58 59 // Cancel closes all channels and cleans up underlying structures. 60 Cancel() 61 } 62 63 // CancelCallback is a callback function executed when cancelling Future. 64 type CancelCallback func(Future) 65 66 type future struct { 67 result chan *packet.Packet 68 actor *host.Host 69 request *packet.Packet 70 requestID network.RequestID 71 cancelCallback CancelCallback 72 finished uint32 73 } 74 75 // NewFuture creates new Future. 76 func NewFuture(requestID network.RequestID, actor *host.Host, msg *packet.Packet, cancelCallback CancelCallback) Future { 77 metrics.NetworkFutures.WithLabelValues(msg.Type.String()).Inc() 78 return &future{ 79 result: make(chan *packet.Packet, 1), 80 actor: actor, 81 request: msg, 82 requestID: requestID, 83 cancelCallback: cancelCallback, 84 } 85 } 86 87 // ID returns RequestID of packet. 88 func (future *future) ID() network.RequestID { 89 return future.requestID 90 } 91 92 // Actor returns Host address that was used to create packet. 93 func (future *future) Actor() *host.Host { 94 return future.actor 95 } 96 97 // Request returns original request packet. 98 func (future *future) Request() *packet.Packet { 99 return future.request 100 } 101 102 // Result returns result packet channel. 103 func (future *future) Result() <-chan *packet.Packet { 104 return future.result 105 } 106 107 // SetResult write packet to the result channel. 108 func (future *future) SetResult(msg *packet.Packet) { 109 if atomic.CompareAndSwapUint32(&future.finished, 0, 1) { 110 future.result <- msg 111 future.finish() 112 } 113 } 114 115 // GetResult gets the future result from Result() channel with a timeout set to `duration`. 116 func (future *future) GetResult(duration time.Duration) (*packet.Packet, error) { 117 select { 118 case result, ok := <-future.Result(): 119 if !ok { 120 return nil, ErrChannelClosed 121 } 122 return result, nil 123 case <-time.After(duration): 124 future.Cancel() 125 metrics.NetworkPacketTimeoutTotal.WithLabelValues(future.request.Type.String()).Inc() 126 return nil, ErrTimeout 127 } 128 } 129 130 // Cancel allows to cancel Future processing. 131 func (future *future) Cancel() { 132 if atomic.CompareAndSwapUint32(&future.finished, 0, 1) { 133 future.finish() 134 metrics.NetworkFutures.WithLabelValues(future.request.Type.String()).Dec() 135 } 136 } 137 138 func (future *future) finish() { 139 close(future.result) 140 future.cancelCallback(future) 141 }