Skip to content

Commit e17d6b1

Browse files
authored
Merge pull request #189 from matter-labs/websocketsFix
Websockets improvements and fixes
2 parents 282f919 + 6f09b81 commit e17d6b1

File tree

9 files changed

+568
-41
lines changed

9 files changed

+568
-41
lines changed

Documentation/Usage.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@
3737
- *[Infura Websocket Provider](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#infura-websocket-provider)*
3838
- [Connect to Infura endpoint](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#connect-to-infura-endpoint)
3939
- [Connect to custom endpoint with API similar to Infura WSS endpoint](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#connect-to-custom-endpoint-with-api-similar-to-infura-wss-endpoint)
40-
- [Create a filter in the node to notify when something happened](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#create-a-filter-in-the-node-to-notify-when-something-happened)
40+
- [Set a filter in the node to notify when something happened](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#set-a-filter-in-the-node-to-notify-when-something-happened)
4141
- [Get new pending transactions](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#get-new-pending-transactions)
4242
- [Create a new subscription over particular events](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#create-a-new-subscription-over-particular-events)
4343
- [Subscribe on new pending transactions](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#subscribe-on-new-pending-transactions)
44+
- [Subscribe on logs](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#subscribe-on-logs)
45+
- [Subscribe on new heads](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#subscribe-on-new-heads)
4446
- **[ENS](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#ens)**
4547
- [Registry](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#registry)
4648
- [Resolver](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#resolver)
@@ -410,18 +412,28 @@ socketProvider = InfuraWebsocketProvider.connectToInfuraSocket(.Mainnet, delegat
410412
socketProvider = InfuraWebsocketProvider.connectToSocket("ws://your.endpoint", delegate: delegate)
411413
```
412414

413-
#### Create a filter in the node to notify when something happened
415+
#### Set a filter in the node to notify when something happened
414416

415417
To study possible filters read [Infura WSS filters documentation](https://infura.io/docs/ethereum/wss/introduction)
416418

417419
```swift
418-
try! socketProvider.filter(method: <InfuraWebsocketMethod>, params: <[Encodable]?>)
420+
// Getting logs
421+
try! socketProvider.setFilterAndGetLogs(method: <InfuraWebsocketMethod>, params: <[Encodable]?>)
422+
// Getting changes
423+
try! socketProvider.setFilterAndGetChanges(method: <InfuraWebsocketMethod>, params: <[Encodable]?>)
424+
```
425+
Or you can provide parameters in more convenient way:
426+
```swift
427+
// Getting logs
428+
try! socketProvider.setFilterAndGetLogs(method: <InfuraWebsocketMethod>, address: <EthereumAddress?>, fromBlock: <BlockNumber?>, toBlock: <BlockNumber?>, topics: <[String]?>)
429+
// Getting changes
430+
try! socketProvider.setFilterAndGetChanges(method: <InfuraWebsocketMethod>, address: <EthereumAddress?>, fromBlock: <BlockNumber?>, toBlock: <BlockNumber?>, topics: <[String]?>)
419431
```
420432

421433
#### Get new pending transactions
422434

423435
```swift
424-
try! socketProvider.filter(method: .newPendingTransactionFilter)
436+
try! socketProvider.setFilterAndGetLogs(method: .newPendingTransactionFilter)
425437
```
426438

427439
#### Create a new subscription over particular events
@@ -438,6 +450,18 @@ try! socketProvider.subscribe(params: <[Encodable]>)
438450
try! socketProvider.subscribeOnNewPendingTransactions()
439451
```
440452

453+
#### Subscribe on logs
454+
455+
```swift
456+
try! socketProvider.subscribeOnLogs(addresses: <[EthereumAddress]?>, topics: <[String]?>)
457+
```
458+
459+
#### Subscribe on new heads
460+
461+
```swift
462+
try! socketProvider.subscribeOnNewHeads()
463+
```
464+
441465
## ENS
442466

443467
You need ENS instance for future actions:

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,12 @@
6868
- *[Infura Websocket Provider](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#infura-websocket-provider)*
6969
- [Connect to Infura endpoint](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#connect-to-infura-endpoint)
7070
- [Connect to custom endpoint with API similar to Infura WSS endpoint](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#connect-to-custom-endpoint-with-api-similar-to-infura-wss-endpoint)
71-
- [Create a filter in the node to notify when something happened](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#create-a-filter-in-the-node-to-notify-when-something-happened)
71+
- [Set a filter in the node to notify when something happened](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#set-a-filter-in-the-node-to-notify-when-something-happened)
7272
- [Get new pending transactions](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#get-new-pending-transactions)
7373
- [Create a new subscription over particular events](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#create-a-new-subscription-over-particular-events)
7474
- [Subscribe on new pending transactions](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#subscribe-on-new-pending-transactions)
75+
- [Subscribe on logs](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#subscribe-on-logs)
76+
- [Subscribe on new heads](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#subscribe-on-new-heads)
7577
- **[ENS](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#ens)**
7678
- [Registry](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#registry)
7779
- [Resolver](https://github.com/matter-labs/web3swift/blob/master/Documentation/Usage.md#resolver)
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
//
2+
// DecodingContainer+AnyCollection.swift
3+
// AnyDecodable
4+
//
5+
// Created by levantAJ on 1/18/19.
6+
// Copyright © 2019 levantAJ. All rights reserved.
7+
//
8+
import Foundation
9+
10+
struct AnyCodingKey: CodingKey {
11+
var stringValue: String
12+
var intValue: Int?
13+
14+
init?(stringValue: String) {
15+
self.stringValue = stringValue
16+
}
17+
18+
init?(intValue: Int) {
19+
self.intValue = intValue
20+
self.stringValue = String(intValue)
21+
}
22+
}
23+
24+
extension KeyedDecodingContainer {
25+
/// Decodes a value of the given type for the given key.
26+
///
27+
/// - parameter type: The type of value to decode.
28+
/// - parameter key: The key that the decoded value is associated with.
29+
/// - returns: A value of the requested type, if present for the given key
30+
/// and convertible to the requested type.
31+
/// - throws: `DecodingError.typeMismatch` if the encountered encoded value
32+
/// is not convertible to the requested type.
33+
/// - throws: `DecodingError.keyNotFound` if `self` does not have an entry
34+
/// for the given key.
35+
/// - throws: `DecodingError.valueNotFound` if `self` has a null entry for
36+
/// the given key.
37+
public func decode(_ type: [Any].Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> [Any] {
38+
var values = try nestedUnkeyedContainer(forKey: key)
39+
return try values.decode(type)
40+
}
41+
42+
/// Decodes a value of the given type for the given key.
43+
///
44+
/// - parameter type: The type of value to decode.
45+
/// - parameter key: The key that the decoded value is associated with.
46+
/// - returns: A value of the requested type, if present for the given key
47+
/// and convertible to the requested type.
48+
/// - throws: `DecodingError.typeMismatch` if the encountered encoded value
49+
/// is not convertible to the requested type.
50+
/// - throws: `DecodingError.keyNotFound` if `self` does not have an entry
51+
/// for the given key.
52+
/// - throws: `DecodingError.valueNotFound` if `self` has a null entry for
53+
/// the given key.
54+
public func decode(_ type: [String: Any].Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> [String: Any] {
55+
let values = try nestedContainer(keyedBy: AnyCodingKey.self, forKey: key)
56+
return try values.decode(type)
57+
}
58+
59+
/// Decodes a value of the given type for the given key, if present.
60+
///
61+
/// This method returns `nil` if the container does not have a value
62+
/// associated with `key`, or if the value is null. The difference between
63+
/// these states can be distinguished with a `contains(_:)` call.
64+
///
65+
/// - parameter type: The type of value to decode.
66+
/// - parameter key: The key that the decoded value is associated with.
67+
/// - returns: A decoded value of the requested type, or `nil` if the
68+
/// `Decoder` does not have an entry associated with the given key, or if
69+
/// the value is a null value.
70+
/// - throws: `DecodingError.typeMismatch` if the encountered encoded value
71+
/// is not convertible to the requested type.
72+
public func decodeIfPresent(_ type: [Any].Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> [Any]? {
73+
guard contains(key),
74+
try decodeNil(forKey: key) == false else { return nil }
75+
return try decode(type, forKey: key)
76+
}
77+
78+
/// Decodes a value of the given type for the given key, if present.
79+
///
80+
/// This method returns `nil` if the container does not have a value
81+
/// associated with `key`, or if the value is null. The difference between
82+
/// these states can be distinguished with a `contains(_:)` call.
83+
///
84+
/// - parameter type: The type of value to decode.
85+
/// - parameter key: The key that the decoded value is associated with.
86+
/// - returns: A decoded value of the requested type, or `nil` if the
87+
/// `Decoder` does not have an entry associated with the given key, or if
88+
/// the value is a null value.
89+
/// - throws: `DecodingError.typeMismatch` if the encountered encoded value
90+
/// is not convertible to the requested type.
91+
public func decodeIfPresent(_ type: [String: Any].Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> [String: Any]? {
92+
guard contains(key),
93+
try decodeNil(forKey: key) == false else { return nil }
94+
return try decode(type, forKey: key)
95+
}
96+
}
97+
98+
private extension KeyedDecodingContainer {
99+
func decode(_ type: [String: Any].Type) throws -> [String: Any] {
100+
var dictionary: [String: Any] = [:]
101+
for key in allKeys {
102+
if try decodeNil(forKey: key) {
103+
dictionary[key.stringValue] = NSNull()
104+
} else if let bool = try? decode(Bool.self, forKey: key) {
105+
dictionary[key.stringValue] = bool
106+
} else if let string = try? decode(String.self, forKey: key) {
107+
dictionary[key.stringValue] = string
108+
} else if let int = try? decode(Int.self, forKey: key) {
109+
dictionary[key.stringValue] = int
110+
} else if let double = try? decode(Double.self, forKey: key) {
111+
dictionary[key.stringValue] = double
112+
} else if let dict = try? decode([String: Any].self, forKey: key) {
113+
dictionary[key.stringValue] = dict
114+
} else if let array = try? decode([Any].self, forKey: key) {
115+
dictionary[key.stringValue] = array
116+
}
117+
}
118+
return dictionary
119+
}
120+
}
121+
122+
private extension UnkeyedDecodingContainer {
123+
mutating func decode(_ type: [Any].Type) throws -> [Any] {
124+
var elements: [Any] = []
125+
while !isAtEnd {
126+
if try decodeNil() {
127+
elements.append(NSNull())
128+
} else if let int = try? decode(Int.self) {
129+
elements.append(int)
130+
} else if let bool = try? decode(Bool.self) {
131+
elements.append(bool)
132+
} else if let double = try? decode(Double.self) {
133+
elements.append(double)
134+
} else if let string = try? decode(String.self) {
135+
elements.append(string)
136+
} else if let values = try? nestedContainer(keyedBy: AnyCodingKey.self),
137+
let element = try? values.decode([String: Any].self) {
138+
elements.append(element)
139+
} else if var values = try? nestedUnkeyedContainer(),
140+
let element = try? values.decode([Any].self) {
141+
elements.append(element)
142+
}
143+
}
144+
return elements
145+
}
146+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
//
2+
// EncodingContainer+AnyCollection.swift
3+
// AnyDecodable
4+
//
5+
// Created by ShopBack on 1/19/19.
6+
// Copyright © 2019 levantAJ. All rights reserved.
7+
//
8+
import Foundation
9+
10+
extension KeyedEncodingContainer {
11+
/// Encodes the given value for the given key.
12+
///
13+
/// - parameter value: The value to encode.
14+
/// - parameter key: The key to associate the value with.
15+
/// - throws: `EncodingError.invalidValue` if the given value is invalid in
16+
/// the current context for this format.
17+
public mutating func encode(_ value: [String: Any], forKey key: KeyedEncodingContainer<K>.Key) throws {
18+
var container = nestedContainer(keyedBy: AnyCodingKey.self, forKey: key)
19+
try container.encode(value)
20+
}
21+
22+
/// Encodes the given value for the given key.
23+
///
24+
/// - parameter value: The value to encode.
25+
/// - parameter key: The key to associate the value with.
26+
/// - throws: `EncodingError.invalidValue` if the given value is invalid in
27+
/// the current context for this format.
28+
public mutating func encode(_ value: [Any], forKey key: KeyedEncodingContainer<K>.Key) throws {
29+
var container = nestedUnkeyedContainer(forKey: key)
30+
try container.encode(value)
31+
}
32+
33+
/// Encodes the given value for the given key if it is not `nil`.
34+
///
35+
/// - parameter value: The value to encode.
36+
/// - parameter key: The key to associate the value with.
37+
/// - throws: `EncodingError.invalidValue` if the given value is invalid in
38+
/// the current context for this format.
39+
public mutating func encodeIfPresent(_ value: [String: Any]?, forKey key: KeyedEncodingContainer<K>.Key) throws {
40+
if let value = value {
41+
var container = nestedContainer(keyedBy: AnyCodingKey.self, forKey: key)
42+
try container.encode(value)
43+
} else {
44+
try encodeNil(forKey: key)
45+
}
46+
}
47+
48+
/// Encodes the given value for the given key if it is not `nil`.
49+
///
50+
/// - parameter value: The value to encode.
51+
/// - parameter key: The key to associate the value with.
52+
/// - throws: `EncodingError.invalidValue` if the given value is invalid in
53+
/// the current context for this format.
54+
public mutating func encodeIfPresent(_ value: [Any]?, forKey key: KeyedEncodingContainer<K>.Key) throws {
55+
if let value = value {
56+
var container = nestedUnkeyedContainer(forKey: key)
57+
try container.encode(value)
58+
} else {
59+
try encodeNil(forKey: key)
60+
}
61+
}
62+
}
63+
64+
private extension KeyedEncodingContainer where K == AnyCodingKey {
65+
mutating func encode(_ value: [String: Any]) throws {
66+
for (k, v) in value {
67+
let key = AnyCodingKey(stringValue: k)!
68+
switch v {
69+
case is NSNull:
70+
try encodeNil(forKey: key)
71+
case let string as String:
72+
try encode(string, forKey: key)
73+
case let int as Int:
74+
try encode(int, forKey: key)
75+
case let bool as Bool:
76+
try encode(bool, forKey: key)
77+
case let double as Double:
78+
try encode(double, forKey: key)
79+
case let dict as [String: Any]:
80+
try encode(dict, forKey: key)
81+
case let array as [Any]:
82+
try encode(array, forKey: key)
83+
default:
84+
debugPrint("⚠️ Unsuported type!", v)
85+
continue
86+
}
87+
}
88+
}
89+
}
90+
91+
private extension UnkeyedEncodingContainer {
92+
/// Encodes the given value.
93+
///
94+
/// - parameter value: The value to encode.
95+
/// - throws: `EncodingError.invalidValue` if the given value is invalid in
96+
/// the current context for this format.
97+
mutating func encode(_ value: [Any]) throws {
98+
for v in value {
99+
switch v {
100+
case is NSNull:
101+
try encodeNil()
102+
case let string as String:
103+
try encode(string)
104+
case let int as Int:
105+
try encode(int)
106+
case let bool as Bool:
107+
try encode(bool)
108+
case let double as Double:
109+
try encode(double)
110+
case let dict as [String: Any]:
111+
try encode(dict)
112+
case let array as [Any]:
113+
var values = nestedUnkeyedContainer()
114+
try values.encode(array)
115+
default:
116+
debugPrint("⚠️ Unsuported type!", v)
117+
}
118+
}
119+
}
120+
121+
/// Encodes the given value.
122+
///
123+
/// - parameter value: The value to encode.
124+
/// - throws: `EncodingError.invalidValue` if the given value is invalid in
125+
/// the current context for this format.
126+
mutating func encode(_ value: [String: Any]) throws {
127+
var container = self.nestedContainer(keyedBy: AnyCodingKey.self)
128+
try container.encode(value)
129+
}
130+
}

Sources/web3swift/Web3/Web3+Eth+Websocket.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ extension web3.Eth {
3131

3232
public func getLatestPendingTransactions(forDelegate delegate: Web3SocketDelegate) throws {
3333
let provider = try getWebsocketProvider(forDelegate: delegate)
34-
try provider.filter(method: .newPendingTransactionFilter)
34+
try provider.setFilterAndGetChanges(method: .newPendingTransactionFilter)
3535
}
3636

3737
public func subscribeOnPendingTransactions(forDelegate delegate: Web3SocketDelegate) throws {

0 commit comments

Comments
 (0)