diff --git a/README.md b/README.md index 46479f5..024281c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ A browser-in-browser "proxy" server that allows to use historical / vintage web * Scroll web page by clicking on the in-image scroll bar. * WRP also allows **a single tall image without the vertical scrollbar** and use client scrolling. To enable this, simply height **H** to `0` . However this should not be used with old and low spec clients. Such tall images will be very large, take a lot of memory and long time to process, especially for GIFs. * Do not use client browser history-back, instead use **Bk** button in the app. -* You can re-capture page screenshot without reloading by using **St** (Stop). +* You can re-capture page screenshot without reloading by using **St** (Stop). This is useful if page didn't render fully before screenshot is taken. * You can also reload and re-capture current page with **Re** (Reload). * To send keystrokes, fill **K** input box and press **Go**. There also are buttons for backspace, enter and arrow keys. * Prefer PNG over GIF if your browser supports it. PNG is much faster, whereas GIF requires a lot of additional processing on both client and server to encode/decode. diff --git a/wrp.go b/wrp.go index 67e37e6..1b1cc67 100644 --- a/wrp.go +++ b/wrp.go @@ -18,6 +18,7 @@ import ( "image/color/palette" "image/gif" "image/png" + "io" "io/ioutil" "log" "math" @@ -42,20 +43,20 @@ import ( const version = "4.6.0" var ( - addr = flag.String("l", ":8080", "Listen address:port, default :8080") - headless = flag.Bool("h", true, "Headless mode / hide browser window (default true)") - noDel = flag.Bool("n", false, "Do not free maps and images after use") - defType = flag.String("t", "gif", "Image type: gif|png") - fgeom = flag.String("g", "1152x600x216", "Geometry: width x height x colors, height can be 0 for unlimited") - htmFnam = flag.String("ui", "wrp.html", "HTML template file for the UI") - delay = flag.Duration("s", 2*time.Second, "Delay/sleep after page is rendered and before screenshot is taken") - srv http.Server - ctx context.Context - cancel context.CancelFunc - img = make(map[string]bytes.Buffer) - ismap = make(map[string]wrpReq) - defGeom geom - htmlTmpl *template.Template + addr = flag.String("l", ":8080", "Listen address:port, default :8080") + headless = flag.Bool("h", true, "Headless mode / hide browser window (default true)") + noDel = flag.Bool("n", false, "Do not free maps and images after use") + defType = flag.String("t", "gif", "Image type: gif|png") + fgeom = flag.String("g", "1152x600x216", "Geometry: width x height x colors, height can be 0 for unlimited") + htmFnam = flag.String("ui", "wrp.html", "HTML template file for the UI") + delay = flag.Duration("s", 2*time.Second, "Delay/sleep after page is rendered and before screenshot is taken") + srv http.Server + actx, ctx context.Context + acncl, cncl context.CancelFunc + img = make(map[string]bytes.Buffer) + ismap = make(map[string]wrpReq) + defGeom geom + htmlTmpl *template.Template ) //go:embed *.html @@ -211,19 +212,24 @@ func (rq *wrpReq) action() chromedp.Action { return chromedp.Navigate(rq.url) } -// Process Keyboard and Mouse events or Navigate to the desired URL. +// Navigate to the desired URL. func (rq *wrpReq) navigate() { - err := chromedp.Run(ctx, rq.action()) - if err != nil { - if err.Error() == "context canceled" { - log.Printf("%s Contex cancelled, try again", rq.r.RemoteAddr) - fmt.Fprintf(rq.w, "
%s
-- restarting, try again", err) - ctx, cancel = chromedp.NewContext(context.Background()) - return - } - log.Printf("%s %s", rq.r.RemoteAddr, err) - fmt.Fprintf(rq.w, "
%s
", err) + ctxErr(chromedp.Run(ctx, rq.action()), rq.w) +} + +// Handle context errors +func ctxErr(err error, w io.Writer) { + if err == nil { + return } + log.Printf("Context error: %s", err) + fmt.Fprintf(w, "Context error: %s
\n", err) + if err.Error() != "context canceled" { + return + } + ctx, cncl = chromedp.NewContext(actx) + log.Printf("Created new context, try again") + fmt.Fprintln(w, "Created new context, try again") } // https://github.com/chromedp/chromedp/issues/979 @@ -283,7 +289,6 @@ func gifPalette(i image.Image, n int64) image.Image { // Capture currently rendered web page to an image and fake ISMAP func (rq *wrpReq) capture() { - var err error var styles []*css.ComputedStyleProperty var r, g, b int var h int64 @@ -315,18 +320,7 @@ func (rq *wrpReq) capture() { chromedp.Sleep(*delay), // TODO(tenox): find a better way to determine if page is rendered ) // Capture screenshot... - err = chromedp.Run(ctx, chromedpCaptureScreenshot(&pngcap, rq.height)) - if err != nil { - if err.Error() == "context canceled" { - log.Printf("%s Contex cancelled, try again", rq.r.RemoteAddr) - fmt.Fprintf(rq.w, "
%s
-- restarting, try again", err) - ctx, cancel = chromedp.NewContext(context.Background()) - return - } - log.Printf("%s Failed to capture screenshot: %s\n", rq.r.RemoteAddr, err) - fmt.Fprintf(rq.w, "
Unable to capture screenshot:
%s
\n", err) - return - } + ctxErr(chromedp.Run(ctx, chromedpCaptureScreenshot(&pngcap, rq.height)), rq.w) seq := rand.Intn(9999) imgpath := fmt.Sprintf("/img/%04d.%s", seq, rq.imgType) mappath := fmt.Sprintf("/map/%04d.map", seq) @@ -456,7 +450,8 @@ func haltServer(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Shutting down WRP...\n") w.(http.Flusher).Flush() time.Sleep(time.Second * 2) - cancel() + cncl() + acncl() srv.Shutdown(context.Background()) os.Exit(1) } @@ -508,10 +503,10 @@ func main() { chromedp.Flag("headless", *headless), chromedp.Flag("hide-scrollbars", false), ) - actx, acancel := chromedp.NewExecAllocator(context.Background(), opts...) - defer acancel() - ctx, cancel = chromedp.NewContext(actx) - defer cancel() + actx, acncl = chromedp.NewExecAllocator(context.Background(), opts...) + defer acncl() + ctx, cncl = chromedp.NewContext(actx) + defer cncl() rand.Seed(time.Now().UnixNano()) @@ -520,7 +515,8 @@ func main() { go func() { <-c log.Printf("Interrupt - shutting down.") - cancel() + cncl() + acncl() srv.Shutdown(context.Background()) os.Exit(1) }()