-
Notifications
You must be signed in to change notification settings - Fork 4
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
Add websocket support #92
Add websocket support #92
Conversation
b2d340a
to
456aeda
Compare
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.
@HenrikJannsen great PR overall Henrik 💪 .
I've added these comments on a first pass purely doing code review, I'm gonna do some testing ASAP and put my feedback as well.
This is a foundational PR so we might be a bit more strict on this one I hope you don't hate me for it haha :)
shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/di/ClientModule.kt
Show resolved
Hide resolved
shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/market/PriceFormatter.kt
Show resolved
Hide resolved
.../commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt
Outdated
Show resolved
Hide resolved
.../domain/src/commonMain/kotlin/network/bisq/mobile/client/websocket/RequestResponseHandler.kt
Show resolved
Hide resolved
.../domain/src/commonMain/kotlin/network/bisq/mobile/client/websocket/RequestResponseHandler.kt
Outdated
Show resolved
Hide resolved
.../src/commonMain/kotlin/network/bisq/mobile/client/websocket/subscription/ModificationType.kt
Show resolved
Hide resolved
shared/domain/src/iosMain/kotlin/network/bisq/mobile/domain/di/ClientModule.ios.kt
Outdated
Show resolved
Hide resolved
shared/presentation/src/commonMain/kotlin/network/bisq/mobile/client/ClientMainPresenter.kt
Show resolved
Hide resolved
shared/presentation/src/commonMain/kotlin/network/bisq/mobile/client/ClientMainPresenter.kt
Show resolved
Hide resolved
...src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/GettingStartedPresenter.kt
Outdated
Show resolved
Hide resolved
@HenrikJannsen gonna need some help testing this one, I'll reach out on M |
Added a comment at the initial post about the renamed HttpApiApp in Bisq2. |
.../kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt
Show resolved
Hide resolved
e4e3d53
to
ecade78
Compare
rebased to main updates |
ecade78
to
d25e4e3
Compare
android node is working as expected, testing WS clients now |
@HenrikJannsen ok awesome, It works on the 3 apps. I'll add some docs on how to setup the env properly so that its easier for everyone to contribute. There are some things we need to discuss, it looks like each running API instance only supports one client only? This causes issues when using the same API instance with a different device, the app assumes its the other user but obviously the cathash has not been generated in that device and then it won't load properly. We need to think how to solve this and allow support for multiple clients per trusted node ? If this is too complex we can support one for the MVP but soon after work on extending it. Gonna do the last code review and add docs and merge this one in 💪 |
…king values into gradle.properties
1c1ea72
to
0d65a0f
Compare
e627f7d
to
e1a24d3
Compare
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.
Merging as is, please have a look at the comments to discuss/consider for next PR! :)
The main thing to deal with is support for multiple clients per trusted node.
If its fesiable to do for MVP then great, otherwise we just need to refuse connections from any device that is not the one that generated the profile (and therefore the cathash) for security purposes right?
I've added some commits with docs, fix to the crash when it can't connect, some logs and the posibility to configure default networking from gradle.properties.
I tested it though in my LAN but it won't work, let's chat about it when you are avail
Awesome work! 💪
} | ||
}.onFailure { e -> | ||
// TODO give user feedback (we could have a general error screen covering usual | ||
// issues like connection issues and potential solutions) |
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.
👍
@@ -24,48 +28,89 @@ class ClientOfferbookListItemService(private val apiGateway: OfferbookApiGateway | |||
|
|||
// Misc | |||
private var job: Job? = null | |||
private var polling = Polling(10000) { updateOffers() } | |||
private var selectedMarket: MarketListItem? = null |
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.
This "selectedMarket" approach on the markets service limit the market information accessibility for all the software components when any of them selects a market. This is probably not something we want as different components might have different needs to cater for different features.
This is why the architecture suggests to use repositories for holding / saving the data as a separate entity from the services.
Its certainly ok for MVP though just leaving this comment as food-for-thought
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 just use the selectedMarket as trigger to select the market price. If we dont want to be triggered by offer market selection but like in bisq2 with a dropdown at the market price, we just change that.
@@ -19,7 +19,7 @@ package network.bisq.mobile.client.replicated_model.common.currency | |||
import kotlinx.serialization.Serializable | |||
|
|||
@Serializable | |||
class Market( | |||
data class Market( |
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.
should probably be a BaseModel as most of the models introduced in this PR. Leaving as is for now till the need arises.
shared/presentation/src/commonMain/kotlin/network/bisq/mobile/client/ClientMainPresenter.kt
Show resolved
Hide resolved
throw e | ||
} | ||
|
||
return withTimeout(timeoutMillis) { |
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'll add a log for now and we can improve in further PRs
suspend fun dispose() { | ||
log.i { "Disposing request handler for ID: $requestId" } | ||
mutex.withLock { | ||
deferredWebSocketResponse?.cancel() |
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.
leaving this for further PRs
import network.bisq.mobile.utils.Logging | ||
import network.bisq.mobile.utils.createUuid | ||
|
||
class WebSocketClient( |
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.
leaving this for further PR dev
} | ||
|
||
suspend fun unSubscribe(topic: Topic, requestId: String) { | ||
//todo |
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.
leaving this for next PR
...monMain/kotlin/network/bisq/mobile/client/websocket/rest_api_proxy/WebSocketRestApiClient.kt
Outdated
Show resolved
Hide resolved
…pect that class naming
4fe88d2
to
6c6154a
Compare
Currently implemented are those topics:
We use the same patter as in the 'Easybind' observer library we use in JavaFx where you get the existing data delivered when subscribing the observer. That is very handy as otherwise one need to do the extra call (as needed in default JavaFx observers). So when we subscribe to a topic we get returned the available data as response to our subscribe request.
For MARKET_PRICE and NUM_OFFERS we get the full map of quotes or numOffers per market code. It would be wasteful to do a new subscribe and unsubscribe every time the user changes the currency. So we keep the data in a map and take out the actual number depending on the selected market.
For OFFERS we dont want to get the full data set at each change as that could be a significant data size.
Instead we use a ModificationType (REPLACE, ADDED, REMOVED) to signal if data was added, removed or if we want to replace the whole data set. The default for the MARKET_PRICE and NUM_OFFERS is REPLACE. For OFFERS we support ADDED/REMOVED to insert items or remove them.
We can send a parameter for subscribing to a topic like currency code, in which case we only would get updates for that currency. If the parameter is not set we get all data. We also handle here the full map of offers per currency, as it would be wasteful to subscribe/unsubscribe at each change of markets.
The payload we get is deserialized to the expected data type at the consumer who knows what data to expect. The generic code does not deserialize that data due lack of type info. Maybe there are some magic hacks to get that resolved as we store the type info in the topic, but I did not get that working so far.
So adding new topics is just to add the topic with its expected type and the consumer defines what type to expect.
We will see with the next user cases if that covers all we need.
The events are emitted on a single thread executor on the server per subscriber, thus guaranteeing the order, but additionally we use a sequence number to check if the later received events are new as the one we got already.
Rest API calls over Websockets:
To avoid that we need to create new Tor circuits at each rest api call, we use the existing websocket connection to route those http messages to the server and there it will get unpacked to call the local rest api endpoints.
So far most rest api calls have been anyway replaced by the websocket subscribe calls. Only the getMarkets is a GET request to the rest api endpoint (though that could be omitted as the markets are a rather static list and only change if we add a market to the price node).
With POST calls there is still a problem (likely on the server side), so we use the normal http client and not the websocket client for that.
For testing one need to run the HttpApiApp (former we used the RestApiApp, this was renamed to HttpApiApp and covers both RestApi and WebsocketApi).