This repository was archived by the owner on Dec 10, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathpeer.ts
139 lines (121 loc) · 3.87 KB
/
peer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import * as events from 'events'
import { Protocol, BoundProtocol, Sender } from '../protocol'
import { Server } from '../server'
import { Config } from '../../config'
export interface PeerOptions {
/* Config */
config: Config
/* Peer id */
id?: string
/* Peer address */
address: string
/* Transport name */
transport: string
/* Pass true if peer initiated connection (default: false) */
inbound?: boolean
/* Supported protocols */
protocols?: Protocol[]
/* Server */
server?: Server
}
/**
* Network peer
* @memberof module:net/peer
*/
export class Peer extends events.EventEmitter {
public config: Config
public id: string
public address: string
public inbound: boolean
public server: Server | undefined
public bound: Map<string, BoundProtocol>
protected transport: string
protected protocols: Protocol[]
private _idle: boolean
// Dynamically bound protocol properties
public les: BoundProtocol | undefined
public eth: BoundProtocol | undefined
/**
* Create new peer
* @param {PeerOptions}
*/
constructor(options: PeerOptions) {
super()
this.config = options.config
this.id = options.id ?? ''
this.address = options.address
this.transport = options.transport
this.inbound = options.inbound ?? false
this.protocols = options.protocols ?? []
this.bound = new Map()
this._idle = true
}
/**
* Get idle state of peer
* @type {boolean}
*/
get idle() {
return this._idle
}
/**
* Set idle state of peer
* @type {boolean}
*/
set idle(value) {
this._idle = value
}
/**
* Adds a protocol to this peer given a sender instance. Protocol methods
* will be accessible via a field with the same name as protocol. New methods
* will be added corresponding to each message defined by the protocol, in
* addition to send() and request() methods that takes a message name and message
* arguments. send() only sends a message without waiting for a response, whereas
* request() also sends the message but will return a promise that resolves with
* the response payload.
* @protected
* @param {Protocol} protocol protocol instance
* @param {Sender} sender Sender instance provided by subclass
* @return {Promise}
* @example
*
* await peer.bindProtocol(ethProtocol, sender)
* // Example: Directly call message name as a method on the bound protocol
* const headers1 = await peer.eth.getBlockHeaders(1, 100, 0, 0)
* // Example: Call request() method with message name as first parameter
* const headers2 = await peer.eth.request('getBlockHeaders', 1, 100, 0, 0)
* // Example: Call send() method with message name as first parameter and
* // wait for response message as an event
* peer.eth.send('getBlockHeaders', 1, 100, 0, 0)
* peer.eth.on('message', ({ data }) => console.log(`Received ${data.length} headers`))
*/
async bindProtocol(protocol: Protocol, sender: Sender): Promise<void> {
const bound = await protocol.bind(this, sender)
bound.on('message', (message: any) => {
this.emit('message', message, protocol.name)
})
bound.on('error', (error: Error) => {
this.emit('error', error, protocol.name)
})
this.bound.set(bound.name, bound)
}
/**
* Return true if peer understand the specified protocol name
* @param protocolName
*/
understands(protocolName: string): boolean {
return !!this.bound.get(protocolName)
}
toString(withFullId = false): string {
const properties = {
id: withFullId ? this.id : this.id.substr(0, 8),
address: this.address,
transport: this.transport,
protocols: Array.from(this.bound.keys()),
inbound: this.inbound,
}
return Object.entries(properties)
.filter(([, value]) => value !== undefined && value !== null && value.toString() !== '')
.map((keyValue) => keyValue.join('='))
.join(' ')
}
}