gpt4 book ai didi

用于下载进度的 Golang 和本地 Web 界面?

转载 作者:数据小太阳 更新时间:2023-10-29 03:15:51 25 4
gpt4 key购买 nike

我是 Go 的新手,正在尝试制作一个跨浏览器的应用程序,它可以下载多个带有进度条的 url。 Grab 包可以很好地完成这项工作,如下例所示。现在,我想要一个独立的/可移植的/单一可执行的网络用户界面,它可以在网络浏览器中显示来自以下代码的下载进度?

package main

import (
"fmt"
"github.com/cavaliercoder/grab"
"os"
"time"
)

func main() {
// get URL to download from command args
if len(os.Args) < 2 {
fmt.Fprintf(os.Stderr, "usage: %s url [url]...\n", os.Args[0])
os.Exit(1)
}

urls := os.Args[1:]

// start file downloads, 3 at a time
fmt.Printf("Downloading %d files...\n", len(urls))
respch, err := grab.GetBatch(3, ".", urls...)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}

// start a ticker to update progress every 200ms
t := time.NewTicker(200 * time.Millisecond)

// monitor downloads
completed := 0
inProgress := 0
responses := make([]*grab.Response, 0)
for completed < len(urls) {
select {
case resp := <-respch:
// a new response has been received and has started downloading
// (nil is received once, when the channel is closed by grab)
if resp != nil {
responses = append(responses, resp)
}

case <-t.C:
// clear lines
if inProgress > 0 {
fmt.Printf("\033[%dA\033[K", inProgress)
}

// update completed downloads
for i, resp := range responses {
if resp != nil && resp.IsComplete() {
// print final result
if resp.Error != nil {
fmt.Fprintf(os.Stderr, "Error downloading %s: %v\n", resp.Request.URL(), resp.Error)
} else {
fmt.Printf("Finished %s %d / %d bytes (%d%%)\n", resp.Filename, resp.BytesTransferred(), resp.Size, int(100*resp.Progress()))
}

// mark completed
responses[i] = nil
completed++
}
}

// update downloads in progress
inProgress = 0
for _, resp := range responses {
if resp != nil {
inProgress++
fmt.Printf("Downloading %s %d / %d bytes (%d%%)\033[K\n", resp.Filename, resp.BytesTransferred(), resp.Size, int(100*resp.Progress()))
}
}
}
}

t.Stop()

fmt.Printf("%d files successfully downloaded.\n", len(urls))
}

最佳答案

一种解决方案是使用 websocket,因为要建立连接,它会使用一种特殊的 header ,将浏览器和服务器之间所需的握手次数减少到只有一次,这意味着客户端服务器通信不会阻塞。

此连接将在其整个生命周期内保持事件状态,您可以使用 JavaScript 在此连接中写入或读取数据,就像传统的 TCP 套接字一样。

作为一个实现问题,您可以将由 grab 包组成的结果信息编码为 json 字符串,然后您可以使用 websocket.JSON.Send .

func (cd Codec) Send(ws *Conn, v interface{}) (err error)

在客户端,您可以获得组合的 json 对象,稍后您可以根据您的使用目的和首选技术(canvas、DOM 等)解析和使用该对象。

下面是 websocket 服务器端的片段:

package main

import (
"fmt"
"golang.org/x/net/websocket"
"net/http"
)

type FileInformation struct {
BytesTransferred int
Size string
Filename string
Progress int
}

func Echo(ws *websocket.Conn) {
info := FileInformation{
BytesTransferred: 70,
Size: "1.7MB",
Filename: "test.txt",
Progress: 60,
}

for {
if err := websocket.JSON.Send(ws, info); err != nil {
fmt.Println("Error sending message")
break
}
// if BytesTransferred == 100 break
}
}

func main() {
http.Handle("/", websocket.Handler(Echo))

if err := http.ListenAndServe(":1234", nil); err != nil {
fmt.Println("Cannot iniatiate a websocket connection")
}
}

当然,这些值是硬编码的,如果您想改变传输速度,您可以使用计时器滴答。

用go编写的客户端:

package main

import (
"fmt"
"golang.org/x/net/websocket"
"io"
"os"
)

func main() {
type FileInformation struct {
BytesTransferred int
Size string
Filename string
Progress int
}

if len(os.Args) > 1 && (os.Args[1] == "--help" || os.Args[1] == "-h") {
fmt.Println("Usage : " + os.Args[0] + " ws://localhost:port")
os.Exit(1)
}

conn, err := websocket.Dial(os.Args[1], "", "http://127.0.0.1")
checkError(err)
var info FileInformation

for {
err := websocket.JSON.Receive(conn, &info)
if err != nil {
if err == io.EOF {
break
}
fmt.Println("Couldn't receive msg " + err.Error())
break
}
fmt.Printf("%s", info)

if err := websocket.JSON.Send(conn, info); err != nil {
checkError(err)
}
}
}

func checkError(err error) {
if err != nil {
fmt.Println("Fatal error: " + err.Error())
os.Exit(1)
}
}

在 javascript 中,您可以连接到 websocket 并接收数据:

<script type="text/javascript">
var sock = null;
var wsuri = "ws://127.0.0.1:1234";

window.onload = function() {

console.log("onload");

sock = new WebSocket(wsuri);

sock.onopen = function() {
console.log("connected to " + wsuri);
}

sock.onclose = function(e) {
console.log("connection closed (" + e.code + ")");
}

sock.onmessage = function(e) {
console.log("message received: " + e.data);
// deserialize json data
var json = JSON.parse(e.data);
}
};

function send() {
var msg = document.getElementById('message').value;
sock.send(msg);
};
</script>

关于用于下载进度的 Golang 和本地 Web 界面?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36217363/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com