mirror of
https://github.com/tenox7/wrp.git
synced 2026-07-09 02:16:47 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b9ffea57f | ||
|
|
ef1c4c0760 | ||
|
|
78efc3210d |
167
download.go
Normal file
167
download.go
Normal file
@@ -0,0 +1,167 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/chromedp/cdproto/browser"
|
||||
"github.com/chromedp/chromedp"
|
||||
"github.com/lithammer/shortuuid/v4"
|
||||
)
|
||||
|
||||
var (
|
||||
dlDir string
|
||||
dlNotify = make(chan struct{}, 1)
|
||||
)
|
||||
|
||||
type dlEvent struct {
|
||||
guid string
|
||||
filename string
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
var dlTrack struct {
|
||||
sync.Mutex
|
||||
ev *dlEvent
|
||||
}
|
||||
|
||||
type dlFile struct {
|
||||
name string
|
||||
data []byte
|
||||
}
|
||||
|
||||
var dlCache struct {
|
||||
sync.Mutex
|
||||
files map[string]dlFile
|
||||
}
|
||||
|
||||
func setupDownloads() {
|
||||
if dlDir == "" {
|
||||
var err error
|
||||
dlDir, err = os.MkdirTemp("", "wrp-dl-")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create download dir: %v", err)
|
||||
}
|
||||
dlCache.files = make(map[string]dlFile)
|
||||
}
|
||||
chromedp.ListenTarget(ctx, func(ev interface{}) {
|
||||
switch e := ev.(type) {
|
||||
case *browser.EventDownloadWillBegin:
|
||||
log.Printf("Download started: %s (%s)", e.SuggestedFilename, e.GUID)
|
||||
dlTrack.Lock()
|
||||
dlTrack.ev = &dlEvent{
|
||||
guid: e.GUID,
|
||||
filename: e.SuggestedFilename,
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
dlTrack.Unlock()
|
||||
select {
|
||||
case dlNotify <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
case *browser.EventDownloadProgress:
|
||||
dlTrack.Lock()
|
||||
ev := dlTrack.ev
|
||||
dlTrack.Unlock()
|
||||
if ev == nil || ev.guid != e.GUID {
|
||||
return
|
||||
}
|
||||
if e.State == browser.DownloadProgressStateCompleted || e.State == browser.DownloadProgressStateCanceled {
|
||||
log.Printf("Download %s: %s", e.State, e.GUID)
|
||||
close(ev.done)
|
||||
}
|
||||
}
|
||||
})
|
||||
err := chromedp.Run(ctx,
|
||||
browser.SetDownloadBehavior(browser.SetDownloadBehaviorBehaviorAllowAndName).
|
||||
WithDownloadPath(dlDir).
|
||||
WithEventsEnabled(true),
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Warning: failed to set download behavior: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func resetDownloadState() {
|
||||
dlTrack.Lock()
|
||||
dlTrack.ev = nil
|
||||
dlTrack.Unlock()
|
||||
select {
|
||||
case <-dlNotify:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func waitForDownload() *dlFile {
|
||||
select {
|
||||
case <-dlNotify:
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
return nil
|
||||
}
|
||||
dlTrack.Lock()
|
||||
ev := dlTrack.ev
|
||||
dlTrack.Unlock()
|
||||
if ev == nil {
|
||||
return nil
|
||||
}
|
||||
log.Printf("Waiting for download: %s", ev.filename)
|
||||
select {
|
||||
case <-ev.done:
|
||||
case <-time.After(60 * time.Second):
|
||||
log.Printf("Download timed out: %s", ev.guid)
|
||||
dlTrack.Lock()
|
||||
dlTrack.ev = nil
|
||||
dlTrack.Unlock()
|
||||
return nil
|
||||
}
|
||||
fpath := filepath.Join(dlDir, ev.guid)
|
||||
data, err := os.ReadFile(fpath)
|
||||
dlTrack.Lock()
|
||||
dlTrack.ev = nil
|
||||
dlTrack.Unlock()
|
||||
if err != nil {
|
||||
log.Printf("Failed to read download %s: %v", fpath, err)
|
||||
return nil
|
||||
}
|
||||
os.Remove(fpath)
|
||||
return &dlFile{name: ev.filename, data: data}
|
||||
}
|
||||
|
||||
func cacheDownload(f *dlFile) string {
|
||||
id := shortuuid.New()
|
||||
dlCache.Lock()
|
||||
dlCache.files[id] = *f
|
||||
dlCache.Unlock()
|
||||
log.Printf("Download cached: /dl/%s (%s, %d bytes)", id, f.name, len(f.data))
|
||||
return "/dl/" + id
|
||||
}
|
||||
|
||||
func writeDownload(w http.ResponseWriter, f *dlFile) {
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, f.name))
|
||||
w.Header().Set("Content-Type", http.DetectContentType(f.data))
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(f.data)))
|
||||
w.Write(f.data)
|
||||
w.(http.Flusher).Flush()
|
||||
log.Printf("Download served inline: %s (%d bytes)", f.name, len(f.data))
|
||||
}
|
||||
|
||||
func dlServer(w http.ResponseWriter, r *http.Request) {
|
||||
id := strings.TrimPrefix(r.URL.Path, "/dl/")
|
||||
log.Printf("%s Download request for %s", r.RemoteAddr, id)
|
||||
dlCache.Lock()
|
||||
f, ok := dlCache.files[id]
|
||||
delete(dlCache.files, id)
|
||||
dlCache.Unlock()
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
writeDownload(w, &f)
|
||||
}
|
||||
18
go.mod
18
go.mod
@@ -4,18 +4,18 @@ go 1.26
|
||||
|
||||
require (
|
||||
github.com/MaxHalford/halfgone v0.0.0-20171017091812-482157b86ccb
|
||||
github.com/PuerkitoBio/goquery v1.11.0
|
||||
github.com/breml/rootcerts v0.3.4
|
||||
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d
|
||||
github.com/chromedp/chromedp v0.14.2
|
||||
github.com/PuerkitoBio/goquery v1.12.0
|
||||
github.com/breml/rootcerts v0.3.5
|
||||
github.com/chromedp/cdproto v0.0.0-20260405000525-47a8ff65b46a
|
||||
github.com/chromedp/chromedp v0.15.1
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4
|
||||
github.com/lithammer/shortuuid/v4 v4.2.0
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
|
||||
github.com/tenox7/gip v1.0.1
|
||||
golang.org/x/image v0.36.0
|
||||
golang.org/x/net v0.51.0
|
||||
github.com/tenox7/gip v1.0.2
|
||||
golang.org/x/image v0.39.0
|
||||
golang.org/x/net v0.53.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -26,6 +26,6 @@ require (
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.4.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
golang.org/x/sys v0.42.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/text v0.36.0 // indirect
|
||||
)
|
||||
|
||||
18
go.sum
18
go.sum
@@ -2,14 +2,22 @@ github.com/MaxHalford/halfgone v0.0.0-20171017091812-482157b86ccb h1:YQ+d0g0P0F/
|
||||
github.com/MaxHalford/halfgone v0.0.0-20171017091812-482157b86ccb/go.mod h1:J86XzS1wgzJPjpQmpriJ+SetP17JSQUd9l+HWQK86jA=
|
||||
github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=
|
||||
github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ=
|
||||
github.com/PuerkitoBio/goquery v1.12.0 h1:pAcL4g3WRXekcB9AU/y1mbKez2dbY2AajVhtkO8RIBo=
|
||||
github.com/PuerkitoBio/goquery v1.12.0/go.mod h1:802ej+gV2y7bbIhOIoPY5sT183ZW0YFofScC4q/hIpQ=
|
||||
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
||||
github.com/breml/rootcerts v0.3.4 h1:9i7WNl/ctd9OEAOaTfLy//Wrlfxq/tRQ7v4okYFN9Ys=
|
||||
github.com/breml/rootcerts v0.3.4/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||
github.com/breml/rootcerts v0.3.5 h1:oi7YiZ25HH52+mrKyjrMkcAFfnRDUf6HO8aUDr7RlJI=
|
||||
github.com/breml/rootcerts v0.3.5/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d h1:ZtA1sedVbEW7EW80Iz2GR3Ye6PwbJAJXjv7D74xG6HU=
|
||||
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
|
||||
github.com/chromedp/cdproto v0.0.0-20260405000525-47a8ff65b46a h1:Kk4P1W58eAf+OUGtx51cM7CcJokJuBEmOxxwPdHFH4Q=
|
||||
github.com/chromedp/cdproto v0.0.0-20260405000525-47a8ff65b46a/go.mod h1:cbyjALe67vDvlvdiG9369P8w5U2w6IshwtyD2f2Tvag=
|
||||
github.com/chromedp/chromedp v0.14.2 h1:r3b/WtwM50RsBZHMUm9fsNhhzRStTHrKdr2zmwbZSzM=
|
||||
github.com/chromedp/chromedp v0.14.2/go.mod h1:rHzAv60xDE7VNy/MYtTUrYreSc0ujt2O1/C3bzctYBo=
|
||||
github.com/chromedp/chromedp v0.15.1 h1:EJWiPm7BNqDqjYy6U0lTSL5wNH+iNt9GjC3a4gfjNyQ=
|
||||
github.com/chromedp/chromedp v0.15.1/go.mod h1:CdTHtUqD/dqaFw/cvFWtTydoEQS44wLBuwbMR9EkOY4=
|
||||
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
|
||||
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 h1:BBade+JlV/f7JstZ4pitd4tHhpN+w+6I+LyOS7B4fyU=
|
||||
@@ -39,6 +47,8 @@ github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqd
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
|
||||
github.com/tenox7/gip v1.0.1 h1:yRcHROzwBjV2BhCjnh1y19wIg5Ei5CTMaZ+lx9nMl3Q=
|
||||
github.com/tenox7/gip v1.0.1/go.mod h1:MR/eaUKjLGkYIguDcAUrWyxG58ipjjCrzM92jwGqDno=
|
||||
github.com/tenox7/gip v1.0.2 h1:VQcaQub/bKu87pQZ1PxeSJPcRWpPRcpIGwP70w6ovQ8=
|
||||
github.com/tenox7/gip v1.0.2/go.mod h1:MR/eaUKjLGkYIguDcAUrWyxG58ipjjCrzM92jwGqDno=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
@@ -48,6 +58,8 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
|
||||
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
|
||||
golang.org/x/image v0.39.0 h1:skVYidAEVKgn8lZ602XO75asgXBgLj9G/FE3RbuPFww=
|
||||
golang.org/x/image v0.39.0/go.mod h1:sIbmppfU+xFLPIG0FoVUTvyBMmgng1/XAMhQ2ft0hpA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
@@ -64,6 +76,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -85,6 +99,8 @@ golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -105,6 +121,8 @@ golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
|
||||
16
ismap.go
16
ismap.go
@@ -152,9 +152,11 @@ func (rq *wrpReq) action() chromedp.Action {
|
||||
return chromedp.Navigate(rq.url)
|
||||
}
|
||||
|
||||
// Navigate to the desired URL.
|
||||
func (rq *wrpReq) navigate() {
|
||||
// Navigate to the desired URL, returns the downloaded file if one was triggered.
|
||||
func (rq *wrpReq) navigate() *dlFile {
|
||||
resetDownloadState()
|
||||
ctxErr(chromedp.Run(ctx, rq.action()), rq.w)
|
||||
return waitForDownload()
|
||||
}
|
||||
|
||||
// Handle context errors
|
||||
@@ -170,6 +172,7 @@ func ctxErr(err error, w io.Writer) {
|
||||
return
|
||||
}
|
||||
ctx, cncl = chromedp.NewContext(actx)
|
||||
setupDownloads()
|
||||
log.Printf("Created new context, try again")
|
||||
fmt.Fprintln(w, "Created new context, try again")
|
||||
}
|
||||
@@ -382,7 +385,14 @@ func mapServer(w http.ResponseWriter, r *http.Request) {
|
||||
rq.printUI(uiParams{})
|
||||
return
|
||||
}
|
||||
rq.navigate() // TODO: if error from navigate do not capture
|
||||
if dl := rq.navigate(); dl != nil {
|
||||
if rq.proxy {
|
||||
writeDownload(w, dl)
|
||||
} else {
|
||||
http.Redirect(w, r, cacheDownload(dl), http.StatusFound)
|
||||
}
|
||||
return
|
||||
}
|
||||
if rq.proxy {
|
||||
chromedp.Run(ctx, waitForRender())
|
||||
var loc string
|
||||
|
||||
13
wrp.go
13
wrp.go
@@ -239,7 +239,10 @@ func proxyServer(w http.ResponseWriter, r *http.Request) {
|
||||
chromedp.Run(ctx, chromedp.Location(¤tURL))
|
||||
currentURL = strings.Replace(currentURL, "https://", "http://", 1)
|
||||
if currentURL != strings.Replace(rq.url, "https://", "http://", 1) {
|
||||
rq.navigate()
|
||||
if dl := rq.navigate(); dl != nil {
|
||||
writeDownload(w, dl)
|
||||
return
|
||||
}
|
||||
}
|
||||
rq.url = strings.Replace(rq.url, "https://", "http://", 1)
|
||||
if r.Method == "CONNECT" {
|
||||
@@ -273,7 +276,10 @@ func pageServer(w http.ResponseWriter, r *http.Request) {
|
||||
rq.printUI(uiParams{})
|
||||
return
|
||||
}
|
||||
rq.navigate() // TODO: if error from navigate do not capture
|
||||
if dl := rq.navigate(); dl != nil {
|
||||
http.Redirect(w, r, cacheDownload(dl), http.StatusFound)
|
||||
return
|
||||
}
|
||||
if rq.wrpMode == "html" {
|
||||
rq.captureMarkdown()
|
||||
return
|
||||
@@ -359,12 +365,14 @@ func main() {
|
||||
cncl, acncl = chromedpStart()
|
||||
defer cncl()
|
||||
defer acncl()
|
||||
setupDownloads()
|
||||
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-c
|
||||
log.Printf("Interrupt - shutting down.")
|
||||
os.RemoveAll(dlDir)
|
||||
cncl()
|
||||
acncl()
|
||||
srv.Shutdown(context.Background())
|
||||
@@ -380,6 +388,7 @@ func main() {
|
||||
http.HandleFunc(imgZpfx, imgServerTxt)
|
||||
http.HandleFunc("/proxy.pac", pacServer)
|
||||
http.HandleFunc("/shutdown/", haltServer)
|
||||
http.HandleFunc("/dl/", dlServer)
|
||||
http.HandleFunc("/favicon.ico", http.NotFound)
|
||||
|
||||
log.Printf("Default Img Type: %v, Geometry: %+v", *defType, defGeom)
|
||||
|
||||
Reference in New Issue
Block a user