@@ -10,9 +10,11 @@ import Starscream
1010import PromiseKit
1111import BigInt
1212import Foundation
13+ import EthereumAddress
1314
1415extension web3 . Eth {
15- public func getLatestPendingTransactions( forDelegate delegate: Web3SocketDelegate ) throws {
16+
17+ public func getWebsocketProvider( forDelegate delegate: Web3SocketDelegate ) throws -> InfuraWebsocketProvider {
1618 var infuraWSProvider : InfuraWebsocketProvider
1719 if !( provider is InfuraWebsocketProvider ) {
1820 guard let infuraNetwork = provider. network else {
@@ -26,7 +28,17 @@ extension web3.Eth {
2628 infuraWSProvider = provider as! InfuraWebsocketProvider
2729 }
2830 infuraWSProvider. connectSocket ( )
29- try infuraWSProvider. subscribeOn ( method: . newPendingTransactionFilter)
31+ return infuraWSProvider
32+ }
33+
34+ public func getLatestPendingTransactions( forDelegate delegate: Web3SocketDelegate ) throws {
35+ let provider = try getWebsocketProvider ( forDelegate: delegate)
36+ try provider. filter ( method: . newPendingTransactionFilter)
37+ }
38+
39+ public func subscribeOnPendingTransactions( forDelegate delegate: Web3SocketDelegate ) throws {
40+ let provider = try getWebsocketProvider ( forDelegate: delegate)
41+ try provider. subscribeOnNewPendingTransactions ( )
3042 }
3143}
3244
@@ -35,20 +47,40 @@ public protocol IWebsocketProvider {
3547 var delegate : Web3SocketDelegate { get set }
3648 func connectSocket( ) throws
3749 func disconnectSocket( ) throws
50+ func writeMessage( string: String )
51+ func writeMessage( data: Data )
3852}
3953
4054public enum InfuraWebsocketMethod : String , Encodable {
4155
4256 case newPendingTransactionFilter = " eth_newPendingTransactionFilter "
4357 case getFilterChanges = " eth_getFilterChanges "
58+ case newFilter = " eth_newFilter "
59+ case newBlockFilter = " eth_newBlockFilter "
60+ case getFilterLogs = " eth_getFilterLogs "
61+ case uninstallFilter = " eth_uninstallFilter "
62+ case subscribe = " eth_subscribe "
63+ case unsubscribe = " eth_unsubscribe "
4464
45- public var requiredNumOfParameters : Int {
65+ public var requiredNumOfParameters : Int ? {
4666 get {
4767 switch self {
4868 case . newPendingTransactionFilter:
4969 return 0
5070 case . getFilterChanges:
5171 return 1
72+ case . newFilter:
73+ return nil
74+ case . newBlockFilter:
75+ return 0
76+ case . getFilterLogs:
77+ return nil
78+ case . uninstallFilter:
79+ return 1
80+ case . subscribe:
81+ return nil
82+ case . unsubscribe:
83+ return 1
5284 }
5385 }
5486 }
@@ -88,11 +120,14 @@ public struct InfuraWebsocketRequest: Encodable {
88120
89121public protocol Web3SocketDelegate {
90122 func received( message: Any )
123+ func gotError( error: Error )
91124}
92125
93126public final class InfuraWebsocketProvider : WebsocketProvider {
94- public var subscriptionKey : String ?
95- private var subscriptionTimer : Timer ?
127+ public var filterID : String ?
128+ public var subscriptionIDs = Set < String > ( )
129+ private var subscriptionIDforUnsubscribing : String ? = nil
130+ private var filterTimer : Timer ?
96131
97132 public init ? ( _ network: Networks ,
98133 delegate: Web3SocketDelegate ,
@@ -115,52 +150,110 @@ public final class InfuraWebsocketProvider: WebsocketProvider {
115150 guard let socketProvider = InfuraWebsocketProvider ( network,
116151 delegate: delegate,
117152 keystoreManager: manager) else { return nil }
118- socketProvider. socket . connect ( )
153+ socketProvider. connectSocket ( )
119154 return socketProvider
120155 }
121156
122- public func subscribeOn( method: InfuraWebsocketMethod , params: [ Encodable ] ? = nil ) throws {
123- do {
124- subscriptionTimer? . invalidate ( )
125- subscriptionKey = nil
126- let params = params ?? [ ]
127- let paramsCount = params. count
128- guard method. requiredNumOfParameters == paramsCount else {
129- throw Web3Error . inputError ( desc: " Wrong number of params: need - \( method. requiredNumOfParameters) , got - \( paramsCount) " )
130- }
131- let request = JSONRPCRequestFabric . prepareRequest ( method, parameters: params)
132- let encoder = JSONEncoder ( )
133- let requestData = try encoder. encode ( request)
134- socket. write ( data: requestData)
135- subscriptionTimer = Timer . scheduledTimer ( timeInterval: 1.0 , target: self , selector: #selector( self . getSubscriptionChanges) , userInfo: nil , repeats: true )
136- } catch {
137- throw Web3Error . connectionError
157+ public func writeMessage( method: InfuraWebsocketMethod , params: [ Encodable ] ) throws {
158+ let request = JSONRPCRequestFabric . prepareRequest ( method, parameters: params)
159+ let encoder = JSONEncoder ( )
160+ let requestData = try encoder. encode ( request)
161+ writeMessage ( data: requestData)
162+ }
163+
164+ public func filter( method: InfuraWebsocketMethod , params: [ Encodable ] ? = nil ) throws {
165+ filterTimer? . invalidate ( )
166+ filterID = nil
167+ let params = params ?? [ ]
168+ let paramsCount = params. count
169+ guard method. requiredNumOfParameters == paramsCount || method. requiredNumOfParameters == nil else {
170+ throw Web3Error . inputError ( desc: " Wrong number of params: need - \( method. requiredNumOfParameters!) , got - \( paramsCount) " )
138171 }
172+ try writeMessage ( method: method, params: params)
173+ filterTimer = Timer . scheduledTimer ( timeInterval: 0.1 , target: self , selector: #selector( getFilterChanges) , userInfo: nil , repeats: true )
139174 }
140175
141- @objc public func getSubscriptionChanges( ) {
142- DispatchQueue . global ( ) . async { [ unowned self] in
143- if let key = self . subscriptionKey {
144- self . subscriptionTimer? . invalidate ( )
145- let method = InfuraWebsocketMethod . getFilterChanges
146- let request = JSONRPCRequestFabric . prepareRequest ( method, parameters: [ key] )
147- let encoder = JSONEncoder ( )
148- if let requestData = try ? encoder. encode ( request) {
149- self . socket. write ( data: requestData)
150- }
151- }
176+ @objc public func getFilterChanges( ) throws {
177+ if let id = self . filterID {
178+ filterTimer? . invalidate ( )
179+ let method = InfuraWebsocketMethod . getFilterChanges
180+ try writeMessage ( method: method, params: [ id] )
181+ }
182+ }
183+
184+ public func getFilterLogs( ) throws {
185+ if let id = self . filterID {
186+ let method = InfuraWebsocketMethod . getFilterLogs
187+ try writeMessage ( method: method, params: [ id] )
188+ }
189+ }
190+
191+ public func unistallFilter( ) throws {
192+ if let id = self . filterID {
193+ let method = InfuraWebsocketMethod . uninstallFilter
194+ try writeMessage ( method: method, params: [ id] )
152195 }
153196 }
154197
198+ public func subscribe( params: [ Encodable ] ) throws {
199+ let method = InfuraWebsocketMethod . subscribe
200+ try writeMessage ( method: method, params: params)
201+ }
202+
203+ public func unsubscribe( subscriptionID: String ) throws {
204+ let method = InfuraWebsocketMethod . unsubscribe
205+ subscriptionIDforUnsubscribing = subscriptionID
206+ try writeMessage ( method: method, params: [ subscriptionID] )
207+ }
208+
209+ public func subscribeOnNewHeads( ) throws {
210+ let method = InfuraWebsocketMethod . subscribe
211+ let params = [ " newHeads " ]
212+ try writeMessage ( method: method, params: params)
213+ }
214+
215+ public func subscribeOnNewPendingTransactions( ) throws {
216+ let method = InfuraWebsocketMethod . subscribe
217+ let params = [ " newPendingTransactions " ]
218+ try writeMessage ( method: method, params: params)
219+ }
220+
221+ public func subscribeOnSyncing( ) throws {
222+ guard network != Networks . Kovan else {
223+ throw Web3Error . inputError ( desc: " Can't sync on Kovan " )
224+ }
225+ let method = InfuraWebsocketMethod . subscribe
226+ let params = [ " syncing " ]
227+ try writeMessage ( method: method, params: params)
228+ }
229+
155230 override public func websocketDidReceiveMessage( socket: WebSocketClient , text: String ) {
156231 if let data = text. data ( using: String . Encoding. utf8) ,
157- let dictionary = try ? JSONSerialization . jsonObject ( with: data, options: [ ] ) as? [ String : AnyObject ] {
158- if subscriptionKey == nil ,
232+ let dictionary = try ? JSONSerialization . jsonObject ( with: data, options: [ ] ) as? [ String : Any ] {
233+ if filterID == nil ,
159234 let result = dictionary [ " result " ] as? String {
160- subscriptionKey = result
161- } else {
162- let result = dictionary [ " result " ] as Any
235+ // setting filter id
236+ filterID = result
237+ } else if let params = dictionary [ " params " ] as? [ String : Any ] ,
238+ let subscription = params [ " subscription " ] as? String ,
239+ let result = params [ " result " ] {
240+ // subscription result
241+ subscriptionIDs. insert ( subscription)
163242 delegate. received ( message: result)
243+ } else if let unsubscribed = dictionary [ " result " ] as? Bool {
244+ // unsubsribe result
245+ if unsubscribed == true , let id = subscriptionIDforUnsubscribing {
246+ subscriptionIDs. remove ( id)
247+ } else if let id = subscriptionIDforUnsubscribing {
248+ delegate. gotError ( error: Web3Error . processingError ( desc: " Can \' t unsubscribe \( id) " ) )
249+ } else {
250+ delegate. received ( message: unsubscribed)
251+ }
252+ } else if let message = dictionary [ " result " ] {
253+ // filter result
254+ delegate. received ( message: message)
255+ } else {
256+ delegate. gotError ( error: Web3Error . processingError ( desc: " Can \' t get known result. Message is: \( text) " ) )
164257 }
165258 }
166259 }
@@ -169,15 +262,11 @@ public final class InfuraWebsocketProvider: WebsocketProvider {
169262/// The default websocket provider.
170263public class WebsocketProvider : Web3Provider , IWebsocketProvider , WebSocketDelegate {
171264 public func sendAsync( _ request: JSONRPCrequest , queue: DispatchQueue ) -> Promise < JSONRPCresponse > {
172- if request. method == nil {
173- return Promise ( error: Web3Error . nodeError ( desc: " RPC method is nil " ) )
174- }
175-
176- return Web3HttpProvider . post ( request, providerURL: self . url, queue: queue, session: self . session)
265+ return Promise ( error: Web3Error . inputError ( desc: " Sending is unsupported for Websocket provider. Please, use \' sendMessage \' " ) )
177266 }
178267
179268 public func sendAsync( _ requests: JSONRPCrequestBatch , queue: DispatchQueue ) -> Promise < JSONRPCresponseBatch > {
180- return Web3HttpProvider . post ( requests , providerURL : self . url , queue : queue , session : self . session )
269+ return Promise ( error : Web3Error . inputError ( desc : " Sending is unsupported for Websocket provider. Please, use \' sendMessage \' " ) )
181270 }
182271
183272 public var network : Networks ?
@@ -202,16 +291,22 @@ public class WebsocketProvider: Web3Provider, IWebsocketProvider, WebSocketDeleg
202291 socket = WebSocket ( url: endpoint)
203292 socket. delegate = self
204293 if net == nil {
205- let request = JSONRPCRequestFabric . prepareRequest ( . getNetwork, parameters: [ ] )
206-
207- if let response = try ? Web3HttpProvider . post ( request,
208- providerURL: endpoint,
209- queue: DispatchQueue . global ( qos: . userInteractive) ,
210- session: session) . wait ( ) ,
211- response. error == nil ,
212- let result: String = response. getValue ( ) ,
213- let intNetworkNumber = Int ( result) {
214- network = Networks . fromInt ( intNetworkNumber)
294+ let endpointString = endpoint. absoluteString
295+ if endpointString. hasPrefix ( " wss:// " ) && endpointString. hasSuffix ( " .infura.io/ws " ) {
296+ let networkString = endpointString. replacingOccurrences ( of: " wss:// " , with: " " )
297+ . replacingOccurrences ( of: " .infura.io/ws " , with: " " )
298+ switch networkString {
299+ case " mainnet " :
300+ network = Networks . Mainnet
301+ case " rinkeby " :
302+ network = Networks . Rinkeby
303+ case " ropsten " :
304+ network = Networks . Ropsten
305+ case " kovan " :
306+ network = Networks . Kovan
307+ default :
308+ break
309+ }
215310 }
216311 } else {
217312 network = net
@@ -231,13 +326,21 @@ public class WebsocketProvider: Web3Provider, IWebsocketProvider, WebSocketDeleg
231326 keystoreManager manager: KeystoreManager ? = nil ,
232327 network net: Networks ? = nil ) -> WebsocketProvider {
233328 let socketProvider = WebsocketProvider ( endpoint: endpoint,
234- delegate: delegate,
235- keystoreManager: manager,
236- network: net)
329+ delegate: delegate,
330+ keystoreManager: manager,
331+ network: net)
237332 socketProvider. connectSocket ( )
238333 return socketProvider
239334 }
240335
336+ public func writeMessage( string: String ) {
337+ socket. write ( string: string)
338+ }
339+
340+ public func writeMessage( data: Data ) {
341+ socket. write ( data: data)
342+ }
343+
241344 public func websocketDidReceiveMessage( socket: WebSocketClient , text: String ) {
242345 print ( " got some text: \( text) " )
243346 delegate. received ( message: text)
0 commit comments