Skip to content

Commit 1089629

Browse files
authored
multi: Improve UX when DEX is unreachable. (#3568)
Add a visible overlay to the trade page when the DEX server is disconnected or running an incompatible protocol version. Previously, a version mismatch only produced a generic "DEX auth error" with no explanation. Now the client sends a clear "Server version incompatible" notification and marks the connection as unusable so the overlay displays correctly and the misleading auth error is suppressed.
1 parent 3909738 commit 1089629

File tree

7 files changed

+35
-4
lines changed

7 files changed

+35
-4
lines changed

client/core/bookie.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ var (
2828
bookFeedTimeout = time.Minute
2929

3030
outdatedClientErr = errors.New("outdated client")
31+
outdatedServerErr = errors.New("outdated server")
3132
)
3233

3334
// BookFeed manages a channel for receiving order book updates. It is imperative
@@ -844,6 +845,8 @@ func (dc *dexConnection) refreshServerConfig() (*msgjson.ConfigResult, error) {
844845
err := fmt.Errorf("unsupported server API version %v", apiVer)
845846
if apiVer > supportedAPIVers[len(supportedAPIVers)-1] {
846847
err = fmt.Errorf("%v: %w", err, outdatedClientErr)
848+
} else if apiVer < supportedAPIVers[0] {
849+
err = fmt.Errorf("%v: %w", err, outdatedServerErr)
847850
}
848851
return nil, err
849852
}

client/core/core.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5498,8 +5498,9 @@ func (c *Core) initializeDEXConnection(dc *dexConnection, crypter encrypt.Crypte
54985498
// Pending bonds will be handled by authDEX. Expired bonds will be
54995499
// refunded by rotateBonds.
55005500

5501-
// If the connection is down, authDEX will fail on Send.
5502-
if dc.IsDown() {
5501+
// If the connection is down or unusable (e.g. version mismatch),
5502+
// authDEX will fail.
5503+
if dc.IsDown() || dc.status() != comms.Connected {
55035504
c.log.Warnf("Connection to %v not available for authorization. "+
55045505
"It will automatically authorize when it connects.", dc.acct.host)
55055506
subject, details := c.formatDetails(TopicDEXDisconnected, dc.acct.host)
@@ -8823,6 +8824,13 @@ func sendOutdatedClientNotification(c *Core, dc *dexConnection) {
88238824
c.notify(newUpgradeNote(TopicUpgradeNeeded, subject, details, db.WarningLevel))
88248825
}
88258826

8827+
// sendOutdatedServerNotification will send a notification to the UI that
8828+
// indicates the DEX server is running an incompatible older protocol version.
8829+
func sendOutdatedServerNotification(c *Core, dc *dexConnection) {
8830+
subject, details := c.formatDetails(TopicServerVersionTooOld, dc.acct.host)
8831+
c.notify(newUpgradeNote(TopicServerVersionTooOld, subject, details, db.ErrorLevel))
8832+
}
8833+
88268834
func isOnionHost(addr string) bool {
88278835
host, _, err := net.SplitHostPort(addr)
88288836
if err != nil {
@@ -9032,8 +9040,12 @@ func (c *Core) startDexConnection(acctInfo *db.AccountInfo, dc *dexConnection) e
90329040
if err != nil {
90339041
// Sort out the bonds with current time to indicate refundable bonds.
90349042
categorizeBonds(time.Now().Unix())
9043+
// Mark the connection as unusable so the UI shows disconnected.
9044+
atomic.StoreUint32(&dc.connectionStatus, uint32(comms.Disconnected))
90359045
if errors.Is(err, outdatedClientErr) {
90369046
sendOutdatedClientNotification(c, dc)
9047+
} else if errors.Is(err, outdatedServerErr) {
9048+
sendOutdatedServerNotification(c, dc)
90379049
}
90389050
return err // no dc.acct.dexPubKey
90399051
}
@@ -9067,8 +9079,12 @@ func (c *Core) handleReconnect(host string) {
90679079
// server configuration.
90689080
cfg, err := dc.refreshServerConfig()
90699081
if err != nil {
9082+
// Mark the connection as unusable so the UI shows disconnected.
9083+
atomic.StoreUint32(&dc.connectionStatus, uint32(comms.Disconnected))
90709084
if errors.Is(err, outdatedClientErr) {
90719085
sendOutdatedClientNotification(c, dc)
9086+
} else if errors.Is(err, outdatedServerErr) {
9087+
sendOutdatedServerNotification(c, dc)
90729088
}
90739089
c.log.Errorf("handleReconnect: Unable to apply new configuration for DEX at %s: %v", host, err)
90749090
return

client/core/locale_ntfn.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,10 @@ var originLocale = map[Topic]*translation{
262262
subject: intl.Translation{T: "Upgrade needed"},
263263
template: intl.Translation{T: "You may need to update your client to trade at %s.", Notes: "args: [host]"},
264264
},
265+
TopicServerVersionTooOld: {
266+
subject: intl.Translation{T: "Server version incompatible"},
267+
template: intl.Translation{T: "The server at %s is running an incompatible older protocol version.", Notes: "args: [host]"},
268+
},
265269
TopicMMSnapshotsNotSupported: {
266270
subject: intl.Translation{T: "MM Snapshots Not Supported"},
267271
template: intl.Translation{T: "The server at %s does not support market maker epoch snapshots.", Notes: "args: [host]"},

client/core/notification.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,7 @@ type UpgradeNote struct {
721721

722722
const (
723723
TopicUpgradeNeeded Topic = "UpgradeNeeded"
724+
TopicServerVersionTooOld Topic = "ServerVersionTooOld"
724725
TopicMMSnapshotsNotSupported Topic = "MMSnapshotsNotSupported"
725726
)
726727

client/webserver/locales/en-us.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ var EnUS = map[string]*intl.Translation{
6666
"price": {T: "price"},
6767
"volume": {T: "volume"},
6868
"volume_24": {T: "24 Hr. Volume"},
69+
"Connection to server failed": {T: "Connection to server failed"},
70+
"Waiting to reconnect...": {T: "Waiting to reconnect..."},
6971
"High": {T: "High"},
7072
"Low": {T: "Low"},
7173
"buys": {T: "buys"},

client/webserver/site/src/html/markets.tmpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@
9898
</div>
9999

100100
<div class="flex-grow-1 position-relative">
101+
<div id="disconnectedOverlay" class="d-hide fill-abs flex-center flex-column" style="z-index:10; background-color: rgba(0,0,0,0.5);">
102+
<span class="ico-disconnected fs40 text-danger mb-3"></span>
103+
<span class="fs22 demi">[[[Connection to server failed]]]</span>
104+
<span class="fs16 grey mt-2">[[[Waiting to reconnect...]]]</span>
105+
</div>
101106
<div id="mainContent">
102107

103108
{{- /* ORDER BOOK */ -}}

client/webserver/site/src/js/markets.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,7 @@ export default class MarketsPage extends BasePage {
11351135
let errMsg = intl.prep(intl.ID_CONNECTION_FAILED)
11361136
if (dex.disabled) errMsg = intl.prep(intl.ID_DEX_DISABLED_MSG)
11371137
page.chartErrMsg.textContent = errMsg
1138-
Doc.show(page.chartErrMsg)
1138+
Doc.show(page.chartErrMsg, page.disconnectedOverlay)
11391139
return
11401140
}
11411141

@@ -1147,7 +1147,7 @@ export default class MarketsPage extends BasePage {
11471147
const [bui, qui] = [app().unitInfo(baseID, dex), app().unitInfo(quoteID, dex)]
11481148

11491149
const rateConversionFactor = OrderUtil.RateEncodingFactor / bui.conventional.conversionFactor * qui.conventional.conversionFactor
1150-
Doc.hide(page.maxOrd, page.chartErrMsg)
1150+
Doc.hide(page.maxOrd, page.chartErrMsg, page.disconnectedOverlay)
11511151
if (this.maxEstimateTimer) {
11521152
window.clearTimeout(this.maxEstimateTimer)
11531153
this.maxEstimateTimer = null

0 commit comments

Comments
 (0)