Skip to content
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

Refreshing the page after a finished validation #96

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions assets/svgload.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions assets/websocket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
window.addEventListener("load", function(evt) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently this is called on every page; the execution should be restricted to the results page if results are still unavailable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened issue #97

var ws;
var loc = window.location, new_uri;
if (loc.protocol === "https:") {
new_uri = "wss:";
} else {
new_uri = "ws:";
}
new_uri += "//" + loc.host + "/ws";
ws = new WebSocket(new_uri);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tested it on valid.dev.g-node.org, where it fails here with the browser console message WebSocket connection to 'wss://valid.dev.g-node.org/ws' failed.

ws.onmessage = function(evt) {
// there should be a check for the message
// content, but it is not needed for now
location.reload();
}
});
1 change: 1 addition & 0 deletions cmd/ginvalid/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func registerRoutes(r *mux.Router) {
r.HandleFunc("/results/{validator}/{user}/{repo}", web.Results).Methods("GET")
r.HandleFunc("/results/{validator}/{user}/{repo}/{id}", web.Results).Methods("GET")
r.HandleFunc("/login", web.LoginGet).Methods("GET")
r.HandleFunc("/ws", web.Socket).Methods("GET")
r.HandleFunc("/login", web.LoginPost).Methods("POST")
r.HandleFunc("/logout", web.Logout).Methods("GET")
r.HandleFunc("/repos", web.ListRepos).Methods("GET")
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/google/uuid v1.1.1
github.com/gorilla/handlers v1.4.2
github.com/gorilla/mux v1.7.3
github.com/gorilla/websocket v1.5.0 // indirect
github.com/magiconair/properties v1.8.1 // indirect
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/mattn/go-isatty v0.0.10 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
Expand Down
5 changes: 5 additions & 0 deletions internal/resources/templates/generic_results.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ const GenericResults = `
{{ end }}
</div>
<div class="column" style="width:80%">
{{ if not (eq .LoadingSVG "") }}
<div class="center" style="width: 100px; height: 100px; margin: auto;">
{{ .LoadingSVG }}
</div>
{{ end }}
<hr>
<div>
<pre style="white-space: pre-wrap">{{.Content}}</pre>
Expand Down
1 change: 1 addition & 0 deletions internal/resources/templates/layout.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var Layout = `
<link rel="stylesheet" href="/assets/semantic-2.3.1.min.css">
<link rel="stylesheet" href="/assets/gogs.css">
<link rel="stylesheet" href="/assets/custom.css">
<script src="/assets/websocket.js"></script>
<title>GIN Valid</title>
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@gnode" />
Expand Down
2 changes: 1 addition & 1 deletion internal/web/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ package web

const (
serveralias = "gin"
progressmsg = "A validation job for this repository is currently in progress, please do not leave this page and refresh the page after a while."
progressmsg = "A validation job for this repository is currently in progress. Please do not leave this page. When it is done, it will refresh automatically. You can also refresh this page manually as many times as you wish"
notvalidatedyet = "This repository has not been validated yet. To see the results, update the repository."
)
15 changes: 12 additions & 3 deletions internal/web/results.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ func renderInProgress(w http.ResponseWriter, r *http.Request, badge []byte, vali
resHistory := resultsHistory(validator, user, repo)
loggedUsername := getLoggedUserName(r)
year, _, _ := time.Now().Date()
svgload, err := ioutil.ReadFile("/assets/svgload.svg")
if err != nil {
svgload = []byte("<svg></svg>")
}
info := struct {
Badge template.HTML
Header string
Expand All @@ -249,7 +253,8 @@ func renderInProgress(w http.ResponseWriter, r *http.Request, badge []byte, vali
CurrentYear int
UserName string
*ResultsHistoryStruct
}{template.HTML(badge), head, string(progressmsg), srvcfg.GINAddresses.WebURL, year, loggedUsername, &resHistory}
LoadingSVG template.HTML
}{template.HTML(badge), head, string(progressmsg), srvcfg.GINAddresses.WebURL, year, loggedUsername, &resHistory, template.HTML(svgload)}

err = tmpl.ExecuteTemplate(w, "layout", info)
if err != nil {
Expand Down Expand Up @@ -373,6 +378,7 @@ func renderNIXResults(w http.ResponseWriter, r *http.Request, badge []byte, cont
head := fmt.Sprintf("NIX validation for %s/%s", user, repo)
resHistory := resultsHistory("nix", user, repo)
year, _, _ := time.Now().Date()
svgload := []byte("")
loggedUsername := getLoggedUserName(r)
srvcfg := config.Read()
info := struct {
Expand All @@ -383,7 +389,8 @@ func renderNIXResults(w http.ResponseWriter, r *http.Request, badge []byte, cont
CurrentYear int
UserName string
*ResultsHistoryStruct
}{template.HTML(badge), head, string(content), srvcfg.GINAddresses.WebURL, year, loggedUsername, &resHistory}
LoadingSVG template.HTML
}{template.HTML(badge), head, string(content), srvcfg.GINAddresses.WebURL, year, loggedUsername, &resHistory, template.HTML(svgload)}

err = tmpl.ExecuteTemplate(w, "layout", info)
if err != nil {
Expand Down Expand Up @@ -414,6 +421,7 @@ func renderODMLResults(w http.ResponseWriter, r *http.Request, badge []byte, con
head := fmt.Sprintf("odML validation for %s/%s", user, repo)
resHistory := resultsHistory("odml", user, repo)
loggedUsername := getLoggedUserName(r)
svgload := []byte("")
srvcfg := config.Read()
year, _, _ := time.Now().Date()
info := struct {
Expand All @@ -424,7 +432,8 @@ func renderODMLResults(w http.ResponseWriter, r *http.Request, badge []byte, con
CurrentYear int
UserName string
*ResultsHistoryStruct
}{template.HTML(badge), head, string(content), srvcfg.GINAddresses.WebURL, year, loggedUsername, &resHistory}
LoadingSVG template.HTML
}{template.HTML(badge), head, string(content), srvcfg.GINAddresses.WebURL, year, loggedUsername, &resHistory, template.HTML(svgload)}

err = tmpl.ExecuteTemplate(w, "layout", info)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions internal/web/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ func Logout(w http.ResponseWriter, r *http.Request) {
Expires: time.Time{},
Secure: false, // TODO: Switch when we go live
}
if conn, ok := websockets[cookie.Value]; ok {
conn.Close()
delete(websockets, cookie.Value)
}
http.SetCookie(w, &cookie)
http.Redirect(w, r, "/login", http.StatusFound)
}
Expand Down
39 changes: 32 additions & 7 deletions internal/web/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (

"github.com/google/uuid"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
)

// BidsMessages contains Errors, Warnings and Ignored messages.
Expand Down Expand Up @@ -56,6 +57,8 @@ type Validationcfg struct {
} `yaml:"bidsconfig"`
}

var websockets map[string]*websocket.Conn = make(map[string]*websocket.Conn)

// handleValidationConfig unmarshalles a yaml config file
// from file and returns the resulting Validationcfg struct.
func handleValidationConfig(cfgpath string) (Validationcfg, error) {
Expand Down Expand Up @@ -341,7 +344,7 @@ func validateODML(valroot, resdir string) error {
return nil
}

func runValidatorBoth(validator, repopath, commit, commitname string, gcl *ginclient.Client, automatic bool) string {
func runValidatorBoth(validator, repopath, commit, commitname string, gcl *ginclient.Client, automatic bool, r *http.Request) string {
respath := filepath.Join(validator, repopath, commit)
go func() {
log.ShowWrite("[Info] Running %s validation on repository %q (%s)", validator, repopath, commitname)
Expand Down Expand Up @@ -474,17 +477,19 @@ func runValidatorBoth(validator, repopath, commit, commitname string, gcl *gincl
if err != nil {
writeValFailure(resdir)
}
cookie, _ := r.Cookie(srvcfg.Settings.CookieName)
websockets[cookie.Value].WriteMessage(websocket.TextMessage, []byte("REFRESH"))
}()
return respath
}
func runValidator(validator, repopath, commit string, gcl *ginclient.Client) {
func runValidator(validator, repopath, commit string, gcl *ginclient.Client, r *http.Request) {
automatic := true
runValidatorBoth(validator, repopath, commit, commit, gcl, automatic)
runValidatorBoth(validator, repopath, commit, commit, gcl, automatic, r)
}

func runValidatorPub(validator, repopath string, gcl *ginclient.Client) string {
func runValidatorPub(validator, repopath string, gcl *ginclient.Client, r *http.Request) string {
automatic := false
return runValidatorBoth(validator, repopath, uuid.New().String(), "HEAD", gcl, automatic)
return runValidatorBoth(validator, repopath, uuid.New().String(), "HEAD", gcl, automatic, r)
}

// writeValFailure writes a badge and page content for when a hook payload is
Expand Down Expand Up @@ -555,6 +560,26 @@ func renderValidationForm(w http.ResponseWriter, r *http.Request, errMsg string)
tmpl.Execute(w, &data)
}

// Socket creates the websocket for async communication (refreshing the page)
func Socket(w http.ResponseWriter, r *http.Request) {
srvcfg := config.Read()
cookie, err := r.Cookie(srvcfg.Settings.CookieName)
if err != nil {
fail(w, r, http.StatusUnauthorized, "You are not logged in")
return
}
var upgrader = websocket.Upgrader{}
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
fail(w, r, http.StatusServiceUnavailable, "Cannot open websocket")
return
}
if conn, ok := websockets[cookie.Value]; ok {
conn.Close()
}
websockets[cookie.Value] = conn
}

// PubValidatePost parses the POST data from the root form and calls the
// validator using the built-in ServiceWaiter.
func PubValidatePost(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -597,7 +622,7 @@ func PubValidatePost(w http.ResponseWriter, r *http.Request) {
return
}

respath := runValidatorPub(validator, repopath, gcl)
respath := runValidatorPub(validator, repopath, gcl, r)
http.Redirect(w, r, filepath.Join("results", respath), http.StatusFound)
}

Expand Down Expand Up @@ -679,7 +704,7 @@ func Validate(w http.ResponseWriter, r *http.Request) {

log.ShowWrite("[Info] Got user %s. Checking repo", gcl.Username)
// Payload is good. Run validator asynchronously and return OK header
runValidator(validator, repopath, commithash, gcl)
runValidator(validator, repopath, commithash, gcl, r)

w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
Expand Down