-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Network] Refactor: #355 Relay client RPC #384
Conversation
dispatcher.send(requestJson) { [weak self] error in | ||
cancellable = requestAcknowledgePublisher | ||
.filter { $0 == request.id } | ||
.sink { (_) in | ||
cancellable?.cancel() | ||
onNetworkAcknowledge(nil) | ||
} | ||
dispatcher.send(message) { [weak self] error in | ||
if let error = error { | ||
self?.logger.debug("Failed to Publish Payload, error: \(error)") | ||
cancellable?.cancel() | ||
onNetworkAcknowledge(error) | ||
} | ||
} | ||
cancellable = requestAcknowledgePublisher | ||
.filter {$0.id == request.id} | ||
.sink { (_) in | ||
cancellable?.cancel() | ||
onNetworkAcknowledge(nil) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any advantage of changing the order?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting up the events before the call prevents any race conditions in case of local socket errors. It's just a good practice
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Socket error will be handled in the completion block on a different thread so I think it's not the case.
Subscription will happen right after send()
method execution as its just adds execution block.
correct me if I am wrong but imo the risk here is close to 0
if send
would be a throwing function, error could happen before subscription but if error happens, you do not even care about subscription. anyway it does not apply for above code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
anyway, you can leave it like this, won't argue 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merhaba birşey sormak istiyorum
@@ -0,0 +1,67 @@ | |||
import JSONRPC | |||
|
|||
public final class RPCHistory { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder how new history can affect existing integrations 🤔
any thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, the history is being used just as a means of message deduplication, so the worst case scenario risk is the SDK receiving a duplicate Subscription
once, which looks like a small trade-off to migrate to a history that can track all requests (the current implementation is generic, so it's bound to a single type of params). What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we still have the transition to version 1.0.0 in the future as an opportunity to include all breaking changes that we need.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we want to avoid any breaking changes that could affect apps on production. But currently I do not think it will be very dangerous. Anyway it's worth to test it before merging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! wish to see a generic networking interactor :)
func wrapToIridium() -> PrefixDecorator<Self> { | ||
return PrefixDecorator(rpcMethod: self, prefix: "iridium") | ||
} | ||
|
||
func wrapToIRN() -> PrefixDecorator<Self> { | ||
return PrefixDecorator(rpcMethod: self, prefix: "irn") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I mentioned before I do not like those wrappings.
I'd prefer concrete types like IrnPublish
etc.
imho, it adds extra unnecessary complexity, couples RelayRPC to wrapToIridium/wrapToIRN
and eventually it will leave some wrapping methods that are not in use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already saw the the protocol be renamed twice, it's better to be prepared for any future changes. Ideally, the RelayClient calls should be refactored in a way that the wrapping is called in just one line, so it's easy to change it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to have a way to configure this in single place (not for every request).
After next protocol renaming is better to replace method than add another wrapToXXX
method 😁
guard let subscriptionId = subscriptions[topic] else { | ||
completion(RelyerError.subscriptionIdNotFound) | ||
return nil | ||
completion(RelayerError.subscriptionIdNotFound) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a good time to rename the error. We no longer use Relayer
anywhere. Errors
would be consistent with other classes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed
subscriptionResponsePublisherSubject.send((response.id, subscriptionId)) | ||
} | ||
case .failure(let rpcError): | ||
logger.error("Received error message from iridium network, code: \(rpcError.code), message: \(rpcError.message)") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we could use relay network
instead of iridium network
? as it is suppose to change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, I've removed references to the "iridium" naming
@discardableResult func publish(topic: String, payload: String, tag: Int, prompt: Bool, onNetworkAcknowledge: @escaping ((Error?) -> Void)) -> Int64 | ||
func publish(topic: String, payload: String, tag: Int, prompt: Bool, onNetworkAcknowledge: @escaping ((Error?) -> Void)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 yeah that was really not necessary to return an id.
4fd874a
to
156e32b
Compare
Package.swift
Outdated
@@ -36,7 +36,7 @@ let package = Package( | |||
path: "Sources/Auth"), | |||
.target( | |||
name: "WalletConnectRelay", | |||
dependencies: ["WalletConnectUtils", "WalletConnectKMS"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WalletConnectUtils depends on JSONRPC, do we need to add JSONRPC dependency here also?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed it
path: "Tests/TestingUtils"), | ||
.testTarget( | ||
name: "WalletConnectUtilsTests", | ||
dependencies: ["WalletConnectUtils"]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed it
let requestJson = try request.json() | ||
try await dispatcher.send(requestJson) | ||
let request = Publish(params: .init(topic: topic, message: payload, ttl: defaultTtl, prompt: prompt, tag: tag)) | ||
.wrapToIridium() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's easy to miss this wrap on new request implementation. We need to configure it once IG
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In one of my first experiments, the wrap + transform into RPC needed to be called only in a single place before sending the message, but I couldn't fit it in the current implementation (because of the callback problems that I was trying to solve). I agree that it should be called just once.
var cancellable: AnyCancellable? | ||
dispatcher.send(requestJson) { [weak self] error in | ||
cancellable = subscriptionResponsePublisher |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible to replace completion with withCheckedThrowingContinuation? To make this method async?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that we need to wait for the acknowledgement with the subscription ID, the same problem that I was talking about in out sync meeting, that I couldn't solve yet
var cancellable: AnyCancellable? | ||
dispatcher.send(requestJson) { [weak self] error in | ||
cancellable = requestAcknowledgePublisher |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to find way how to move requestAcknowledgePublisher subscription out of this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the RelayClient refactor is not over
} | ||
let id: RPCID | ||
let topic: String | ||
let origin: Origin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just noticed it. What is the purpose of origin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Being able to track whether a request was sent from the client or from the peer. Thinking on long term support, I think is a nice thing to have, might be useful in the future
if let request = tryDecode(RPCRequest.self, from: payload) { | ||
if let params = try? request.params?.get(Subscription.Params.self) { | ||
do { | ||
try rpcHistory.set(request, forTopic: params.data.topic, emmitedBy: .remote) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is the only place where we are setting a history record. Should we record history when requesting as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now, it's the only place. I'm in for recording all requests, so we can have a complete history.
closes #355
Overview:
JSONRPC
types into the Relay client target.RelayRPC
protocol.Either
andRPCResponse
.RPCHistory
to track all RPC requests sent and received from the client.Notes:
RPCMethod
protocol could be extracted to utils to be used in other targets for scalability.RPCHistory
is still only replacing the current behavior forSubscription
method.Next steps:
RPCHistory
usage to track all requests and responses, from local and remote origins, to provide a full history.