Skip to content

Commit

Permalink
Keep around loaded data in non-ready state for GUI and web interface
Browse files Browse the repository at this point in the history
This allows to still access the data and recorded history when the
connection to the device fails permanently for some reason.
  • Loading branch information
janh committed Jan 31, 2024
1 parent 03e29b0 commit 64c85d5
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 72 deletions.
10 changes: 8 additions & 2 deletions cmd/gui/gui.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,18 @@ func save() {
mutex.Lock()
defer mutex.Unlock()

if lastMessage.State != string(common.StateReady) {
if lastMessage.State != string(common.StateReady) &&
lastMessage.State != string(common.StatePasswordRequired) &&
lastMessage.State != string(common.StatePassphraseRequired) &&
lastMessage.State != string(common.StateEncryptionPassphraseRequired) &&
lastMessage.State != string(common.StateError) &&
lastMessage.State != string(common.StateLoading) {

return
}

change := c.State()
if change.State != common.StateReady {
if !change.HasData {
return
}

Expand Down
46 changes: 23 additions & 23 deletions cmd/gui/res/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,44 +227,44 @@
element.tabIndex = disabled ? -1 : 0;
}

function updateState(newState, data) {
function updateState(newState, info, data) {
let oldState = state;

if (data !== undefined) {
if (info !== undefined) {
switch (newState) {

case STATE_PASSPHRASE:
fingerprint.innerText = data;
break;

case STATE_READY:
bins = DSLGraphs.decodeBins(data["bins"]);
binsHistory = DSLGraphs.decodeBinsHistory(data["bins_history"]);
var errorsHistory = DSLGraphs.decodeErrorsHistory(data["errors_history"]);
summary.innerHTML = data["summary"];
graphBits.setData(bins);
updateSNRGraph();
graphQLN.setData(bins);
graphHlog.setData(bins);
graphRetransmissionDown.setData(errorsHistory);
graphRetransmissionUp.setData(errorsHistory);
graphErrorsDown.setData(errorsHistory);
graphErrorsUp.setData(errorsHistory);
graphErrorSecondsDown.setData(errorsHistory);
graphErrorSecondsUp.setData(errorsHistory);
fingerprint.innerText = info;
break;

case STATE_ERROR:
overlayError.innerText = data;
overlayError.innerText = info;
break;

}
}

if (data !== undefined) {
bins = DSLGraphs.decodeBins(data["bins"]);
binsHistory = DSLGraphs.decodeBinsHistory(data["bins_history"]);
var errorsHistory = DSLGraphs.decodeErrorsHistory(data["errors_history"]);
summary.innerHTML = data["summary"];
graphBits.setData(bins);
updateSNRGraph();
graphQLN.setData(bins);
graphHlog.setData(bins);
graphRetransmissionDown.setData(errorsHistory);
graphRetransmissionUp.setData(errorsHistory);
graphErrorsDown.setData(errorsHistory);
graphErrorsUp.setData(errorsHistory);
graphErrorSecondsDown.setData(errorsHistory);
graphErrorSecondsUp.setData(errorsHistory);
}

if (newState != oldState) {
state = newState;

setLinkDisabled(buttonSave, state != STATE_READY);
setLinkDisabled(buttonSave, data === undefined);
setLinkDisabled(buttonDisconnect,
state != STATE_READY && state != STATE_PASSWORD && state != STATE_PASSPHRASE && state != STATE_ENCRYPTION_PASSPHRASE && state != STATE_ERROR && state != STATE_LOADING);

Expand Down Expand Up @@ -512,7 +512,7 @@
updateState(STATE_INITIALIZING);

window.updateState = function(data) {
updateState(data.state, data.data);
updateState(data.state, data.info, data.data);
}

window.showMessage = function(text) {
Expand Down
51 changes: 40 additions & 11 deletions cmd/web/common/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (
type StateChange struct {
State State

HasData bool
Time time.Time
RawData []byte
Status models.Status
Expand All @@ -56,7 +57,8 @@ type Client struct {
receivers map[chan StateChange]bool
lastStateChange StateChange

client dsl.Client
client dsl.Client
lastData StateChange

interval time.Duration
intervalChanged chan bool
Expand Down Expand Up @@ -189,6 +191,22 @@ func (c *Client) distribute() {
}
}

func (c *Client) stateChangeWithLastData(change StateChange) StateChange {
if !c.lastData.HasData {
return change
}

change.HasData = c.lastData.HasData
change.Time = c.lastData.Time
change.RawData = c.lastData.RawData
change.Status = c.lastData.Status
change.Bins = c.lastData.Bins
change.BinsHistory = c.lastData.BinsHistory
change.ErrorsHistory = c.lastData.ErrorsHistory

return change
}

func (c *Client) connect() {
var err error
var interval = 2 * time.Second
Expand All @@ -214,7 +232,8 @@ func (c *Client) connect() {
}
}

c.changeState <- StateChange{State: StateError, Err: err}
c.changeState <- c.stateChangeWithLastData(
StateChange{State: StateError, Err: err})

select {
case <-c.cancel:
Expand All @@ -236,7 +255,8 @@ func (c *Client) update() {
if clientDesc.SupportedAuthTypes&dsl.AuthTypePassword != 0 && c.config.AuthPassword == nil {
c.config.AuthPassword = func() (string, error) {
if c.password == "" {
c.changeState <- StateChange{State: StatePasswordRequired}
c.changeState <- c.stateChangeWithLastData(
StateChange{State: StatePasswordRequired})

select {
case <-c.cancel:
Expand All @@ -246,7 +266,8 @@ func (c *Client) update() {
c.password = password
}

c.changeState <- StateChange{State: StateLoading}
c.changeState <- c.stateChangeWithLastData(
StateChange{State: StateLoading})
}

return c.password, nil
Expand All @@ -256,7 +277,8 @@ func (c *Client) update() {
if clientDesc.SupportedAuthTypes&dsl.AuthTypePrivateKeys != 0 && c.config.AuthPrivateKeys.Passphrase == nil {
c.config.AuthPrivateKeys.Passphrase = func(fingerprint string) (string, error) {
if c.passphrase[fingerprint] == "" {
c.changeState <- StateChange{State: StatePassphraseRequired, Fingerprint: fingerprint}
c.changeState <- c.stateChangeWithLastData(
StateChange{State: StatePassphraseRequired, Fingerprint: fingerprint})

select {
case <-c.cancel:
Expand All @@ -266,7 +288,8 @@ func (c *Client) update() {
c.passphrase[fingerprint] = passphrase
}

c.changeState <- StateChange{State: StateLoading}
c.changeState <- c.stateChangeWithLastData(
StateChange{State: StateLoading})
}

return c.passphrase[fingerprint], nil
Expand All @@ -276,7 +299,8 @@ func (c *Client) update() {
if clientDesc.SupportsEncryptionPassphrase && c.config.EncryptionPassphrase == nil {
c.config.EncryptionPassphrase = func() (string, error) {
if c.encryptionPassphrase == "" {
c.changeState <- StateChange{State: StateEncryptionPassphraseRequired}
c.changeState <- c.stateChangeWithLastData(
StateChange{State: StateEncryptionPassphraseRequired})

select {
case <-c.cancel:
Expand All @@ -286,7 +310,8 @@ func (c *Client) update() {
c.encryptionPassphrase = encryptionPassphrase
}

c.changeState <- StateChange{State: StateLoading}
c.changeState <- c.stateChangeWithLastData(
StateChange{State: StateLoading})
}

return c.encryptionPassphrase, nil
Expand Down Expand Up @@ -322,8 +347,8 @@ mainloop:
binsHistory.Update(c.client.Status(), c.client.Bins(), now)
errorsHistory.Update(c.client.Status(), now)

c.changeState <- StateChange{
State: StateReady,
c.lastData = StateChange{
HasData: true,
Time: now,
RawData: c.client.RawData(),
Status: c.client.Status(),
Expand All @@ -332,13 +357,17 @@ mainloop:
ErrorsHistory: errorsHistory.Data(),
}

c.changeState <- c.stateChangeWithLastData(
StateChange{State: StateReady})

c.errCount = 0

break

} else {

c.changeState <- StateChange{State: StateError, Err: err}
c.changeState <- c.stateChangeWithLastData(
StateChange{State: StateError, Err: err})

c.errCount++

Expand Down
17 changes: 9 additions & 8 deletions cmd/web/common/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,21 @@ func GetStateMessage(change StateChange) Message {

switch change.State {

case StateReady:
case StatePassphraseRequired:
msg.Info = change.Fingerprint

case StateError:
msg.Info = "failed to load data from device: " + change.Err.Error()

}

if change.HasData {
msg.Data = MessageData{
Summary: getSummaryString(change.Status),
Bins: jsgraphs.EncodeBins(change.Bins),
BinsHistory: jsgraphs.EncodeBinsHistory(change.BinsHistory),
ErrorsHistory: jsgraphs.EncodeErrorsHistory(change.ErrorsHistory),
}

case StatePassphraseRequired:
msg.Data = change.Fingerprint

case StateError:
msg.Data = "failed to load data from device: " + change.Err.Error()

}

return msg
Expand Down
3 changes: 2 additions & 1 deletion cmd/web/common/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import (

type Message struct {
State string `json:"state"`
Info interface{} `json:"info,omitempty"`
Data interface{} `json:"data,omitempty"`
}

func (m Message) JSON() []byte {
dataBytes, err := json.Marshal(m)
if err != nil {
dataBytes = []byte(`{"state":"error","data":"encoding error"}`)
dataBytes = []byte(`{"state":"error","info":"encoding error"}`)
}

return dataBytes
Expand Down
46 changes: 23 additions & 23 deletions cmd/web/static/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,44 +42,44 @@ function setLinkDisabled(element, disabled) {
}
}

function updateState(newState, data) {
function updateState(newState, info, data) {
let oldState = state;

if (data !== undefined) {
if (info !== undefined) {
switch (newState) {

case STATE_PASSPHRASE:
fingerprint.innerText = data;
break;

case STATE_READY:
bins = DSLGraphs.decodeBins(data["bins"]);
binsHistory = DSLGraphs.decodeBinsHistory(data["bins_history"]);
var errorsHistory = DSLGraphs.decodeErrorsHistory(data["errors_history"]);
summary.innerHTML = data["summary"];
graphBits.setData(bins);
updateSNRGraph();
graphQLN.setData(bins);
graphHlog.setData(bins);
graphRetransmissionDown.setData(errorsHistory);
graphRetransmissionUp.setData(errorsHistory);
graphErrorsDown.setData(errorsHistory);
graphErrorsUp.setData(errorsHistory);
graphErrorSecondsDown.setData(errorsHistory);
graphErrorSecondsUp.setData(errorsHistory);
fingerprint.innerText = info;
break;

case STATE_ERROR:
overlayError.innerText = data;
overlayError.innerText = info;
break;

}
}

if (data !== undefined) {
bins = DSLGraphs.decodeBins(data["bins"]);
binsHistory = DSLGraphs.decodeBinsHistory(data["bins_history"]);
var errorsHistory = DSLGraphs.decodeErrorsHistory(data["errors_history"]);
summary.innerHTML = data["summary"];
graphBits.setData(bins);
updateSNRGraph();
graphQLN.setData(bins);
graphHlog.setData(bins);
graphRetransmissionDown.setData(errorsHistory);
graphRetransmissionUp.setData(errorsHistory);
graphErrorsDown.setData(errorsHistory);
graphErrorsUp.setData(errorsHistory);
graphErrorSecondsDown.setData(errorsHistory);
graphErrorSecondsUp.setData(errorsHistory);
}

if (newState != oldState) {
state = newState;

setLinkDisabled(linkSave, state != STATE_READY);
setLinkDisabled(linkSave, data === undefined);

checkboxAutoscale.disabled = state != STATE_READY;
checkboxMinMax.disabled = state != STATE_READY;
Expand Down Expand Up @@ -138,7 +138,7 @@ function startEvents() {

eventSource.onmessage = function(event) {
let message = JSON.parse(event.data);
updateState(message.state, message.data);
updateState(message.state, message.info, message.data);
}

eventSource.onerror = function(event) {
Expand Down
9 changes: 5 additions & 4 deletions cmd/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,16 +179,17 @@ func getStateMessage(change common.StateChange) (msg common.Message) {
case config.HideErrorMessages && change.State == common.StateError:
log.Println(change.Err)

msg.State = string(change.State)
msg.Data = "failed to load data from device: see log message for details"
msg = common.GetStateMessage(change)
msg.Info = "failed to load data from device: see log message for details"

case config.DisableInteractiveAuth &&
(change.State == common.StatePasswordRequired ||
change.State == common.StatePassphraseRequired ||
change.State == common.StateEncryptionPassphraseRequired):

msg = common.GetStateMessage(change)
msg.State = string(common.StateError)
msg.Data = "failed to load data from device: interactive authentication required but not allowed"
msg.Info = "failed to load data from device: interactive authentication required but not allowed"

default:
msg = common.GetStateMessage(change)
Expand Down Expand Up @@ -251,7 +252,7 @@ func handleDownload(w http.ResponseWriter, req *http.Request) {
}

state := c.State()
if state.State != common.StateReady {
if !state.HasData {
http.Error(w, "404 not found", http.StatusNotFound)
return
}
Expand Down

0 comments on commit 64c85d5

Please sign in to comment.