mirror of
https://github.com/boringproxy/boringproxy.git
synced 2025-02-25 18:55:29 -06:00
Implement loading screen for slow requests
This commit is contained in:
parent
9aafa18254
commit
cca211de0e
113
ui_handler.go
113
ui_handler.go
@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/GeertJohan/go.rice"
|
"github.com/GeertJohan/go.rice"
|
||||||
"html/template"
|
"html/template"
|
||||||
@ -9,16 +8,20 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebUiHandler struct {
|
type WebUiHandler struct {
|
||||||
config *BoringProxyConfig
|
config *BoringProxyConfig
|
||||||
db *Database
|
db *Database
|
||||||
api *Api
|
api *Api
|
||||||
auth *Auth
|
auth *Auth
|
||||||
tunMan *TunnelManager
|
tunMan *TunnelManager
|
||||||
box *rice.Box
|
box *rice.Box
|
||||||
headHtml template.HTML
|
headHtml template.HTML
|
||||||
|
pendingRequests map[string]chan string
|
||||||
|
mutex *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
type IndexData struct {
|
type IndexData struct {
|
||||||
@ -41,6 +44,11 @@ type ConfirmData struct {
|
|||||||
CancelUrl string
|
CancelUrl string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LoadingData struct {
|
||||||
|
Head template.HTML
|
||||||
|
TargetUrl string
|
||||||
|
}
|
||||||
|
|
||||||
type AlertData struct {
|
type AlertData struct {
|
||||||
Head template.HTML
|
Head template.HTML
|
||||||
Message string
|
Message string
|
||||||
@ -76,11 +84,13 @@ type TokensData struct {
|
|||||||
|
|
||||||
func NewWebUiHandler(config *BoringProxyConfig, db *Database, api *Api, auth *Auth, tunMan *TunnelManager) *WebUiHandler {
|
func NewWebUiHandler(config *BoringProxyConfig, db *Database, api *Api, auth *Auth, tunMan *TunnelManager) *WebUiHandler {
|
||||||
return &WebUiHandler{
|
return &WebUiHandler{
|
||||||
config: config,
|
config: config,
|
||||||
db: db,
|
db: db,
|
||||||
api: api,
|
api: api,
|
||||||
auth: auth,
|
auth: auth,
|
||||||
tunMan: tunMan,
|
tunMan: tunMan,
|
||||||
|
pendingRequests: make(map[string]chan string),
|
||||||
|
mutex: &sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,6 +301,8 @@ func (h *WebUiHandler) handleWebUiRequest(w http.ResponseWriter, r *http.Request
|
|||||||
cookie := &http.Cookie{Name: "access_token", Value: "", Secure: true, HttpOnly: true}
|
cookie := &http.Cookie{Name: "access_token", Value: "", Secure: true, HttpOnly: true}
|
||||||
http.SetCookie(w, cookie)
|
http.SetCookie(w, cookie)
|
||||||
http.Redirect(w, r, "/#/tunnels", 303)
|
http.Redirect(w, r, "/#/tunnels", 303)
|
||||||
|
case "/loading":
|
||||||
|
h.handleLoading(w, r)
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(404)
|
w.WriteHeader(404)
|
||||||
h.alertDialog(w, r, "Unknown page "+r.URL.Path, "/#/tunnels")
|
h.alertDialog(w, r, "Unknown page "+r.URL.Path, "/#/tunnels")
|
||||||
@ -377,16 +389,57 @@ func (h *WebUiHandler) handleTunnels(w http.ResponseWriter, r *http.Request, tok
|
|||||||
|
|
||||||
func (h *WebUiHandler) handleCreateTunnel(w http.ResponseWriter, r *http.Request, tokenData TokenData) {
|
func (h *WebUiHandler) handleCreateTunnel(w http.ResponseWriter, r *http.Request, tokenData TokenData) {
|
||||||
|
|
||||||
r.ParseForm()
|
pendingId, err := genRandomCode(16)
|
||||||
|
|
||||||
_, err := h.api.CreateTunnel(tokenData, r.Form)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(400)
|
||||||
h.alertDialog(w, r, err.Error(), "/#/tunnels")
|
h.alertDialog(w, r, err.Error(), "/#/tunnels")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(w, r, "/#/tunnels", 303)
|
doneSignal := make(chan string)
|
||||||
|
h.mutex.Lock()
|
||||||
|
h.pendingRequests[pendingId] = doneSignal
|
||||||
|
h.mutex.Unlock()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
|
||||||
|
r.ParseForm()
|
||||||
|
|
||||||
|
_, err := h.api.CreateTunnel(tokenData, r.Form)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(400)
|
||||||
|
h.alertDialog(w, r, err.Error(), "/#/tunnels")
|
||||||
|
}
|
||||||
|
|
||||||
|
doneSignal <- "/#/tunnels"
|
||||||
|
}()
|
||||||
|
|
||||||
|
timeout := make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
timeout <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-timeout:
|
||||||
|
url := fmt.Sprintf("/loading?id=%s", pendingId)
|
||||||
|
|
||||||
|
tmpl, err := h.loadTemplate("loading.tmpl")
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(500)
|
||||||
|
h.alertDialog(w, r, err.Error(), "/#/tunnels")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := &LoadingData{
|
||||||
|
Head: h.headHtml,
|
||||||
|
TargetUrl: url,
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl.Execute(w, data)
|
||||||
|
|
||||||
|
case <-doneSignal:
|
||||||
|
http.Redirect(w, r, "/#/tunnels", 303)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *WebUiHandler) sendLoginPage(w http.ResponseWriter, r *http.Request, code int) {
|
func (h *WebUiHandler) sendLoginPage(w http.ResponseWriter, r *http.Request, code int) {
|
||||||
@ -555,16 +608,36 @@ func (h *WebUiHandler) alertDialog(w http.ResponseWriter, r *http.Request, messa
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *WebUiHandler) handleLoading(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
if r.Method != "GET" {
|
||||||
|
w.WriteHeader(405)
|
||||||
|
h.alertDialog(w, r, "Invalid method for users", "/#/tunnels")
|
||||||
|
}
|
||||||
|
|
||||||
|
r.ParseForm()
|
||||||
|
|
||||||
|
pendingId := r.Form.Get("id")
|
||||||
|
|
||||||
|
h.mutex.Lock()
|
||||||
|
doneSignal := h.pendingRequests[pendingId]
|
||||||
|
h.mutex.Unlock()
|
||||||
|
|
||||||
|
redirUrl := <-doneSignal
|
||||||
|
|
||||||
|
http.Redirect(w, r, redirUrl, 303)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *WebUiHandler) loadTemplate(name string) (*template.Template, error) {
|
func (h *WebUiHandler) loadTemplate(name string) (*template.Template, error) {
|
||||||
|
|
||||||
tmplStr, err := h.box.String(name)
|
tmplStr, err := h.box.String(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("Error reading template " + name)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl, err := template.New(name).Parse(tmplStr)
|
tmpl, err := template.New(name).Parse(tmplStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("Error compiling template " + name)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmpl, nil
|
return tmpl, nil
|
||||||
|
17
webui/loading.tmpl
Normal file
17
webui/loading.tmpl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="refresh" content="0; URL='{{$.TargetUrl}}'" />
|
||||||
|
{{.Head}}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<main>
|
||||||
|
<div class='dialog'>
|
||||||
|
<p>
|
||||||
|
Loading...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user