Improve speed calculation, clean some things up
This commit is contained in:
parent
b92f5cfb43
commit
a90e8d4b2f
126
pkg/irc/dcc.go
126
pkg/irc/dcc.go
@ -18,7 +18,7 @@ import (
|
|||||||
type DCCSend struct {
|
type DCCSend struct {
|
||||||
File string `json:"file"`
|
File string `json:"file"`
|
||||||
IP string `json:"ip"`
|
IP string `json:"ip"`
|
||||||
Port uint16 `json:"port"`
|
Port string `json:"port"`
|
||||||
Length uint64 `json:"length"`
|
Length uint64 `json:"length"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,14 +27,14 @@ func ParseDCCSend(ctcp *CTCP) *DCCSend {
|
|||||||
|
|
||||||
if len(params) > 4 {
|
if len(params) > 4 {
|
||||||
ip, err := strconv.Atoi(params[2])
|
ip, err := strconv.Atoi(params[2])
|
||||||
port, err := strconv.Atoi(params[3])
|
|
||||||
length, err := strconv.Atoi(params[4])
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ip3 := uint32ToIP(ip)
|
length, err := strconv.ParseUint(params[4], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
filename := path.Base(params[1])
|
filename := path.Base(params[1])
|
||||||
if filename == "/" || filename == "." {
|
if filename == "/" || filename == "." {
|
||||||
@ -43,9 +43,9 @@ func ParseDCCSend(ctcp *CTCP) *DCCSend {
|
|||||||
|
|
||||||
return &DCCSend{
|
return &DCCSend{
|
||||||
File: filename,
|
File: filename,
|
||||||
IP: ip3,
|
IP: intToIP(ip),
|
||||||
Port: uint16(port),
|
Port: params[3],
|
||||||
Length: uint64(length),
|
Length: length,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,97 +57,99 @@ func (c *Client) Download(pack *DCCSend) {
|
|||||||
// TODO: ask user if he/she wants to download the file
|
// TODO: ask user if he/she wants to download the file
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Progress <- DownloadProgress{
|
c.Progress <- DownloadProgress{
|
||||||
PercCompletion: 0,
|
File: pack.File,
|
||||||
File: pack.File,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.OpenFile(filepath.Join(c.DownloadFolder, pack.File), os.O_CREATE|os.O_WRONLY, 0644)
|
file, err := os.OpenFile(filepath.Join(c.DownloadFolder, pack.File), os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Progress <- DownloadProgress{
|
c.downloadFailed(pack, err)
|
||||||
PercCompletion: -1,
|
|
||||||
File: pack.File,
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
con, err := net.Dial("tcp", fmt.Sprintf("%s:%d", pack.IP, pack.Port))
|
conn, err := net.Dial("tcp", net.JoinHostPort(pack.IP, pack.Port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Progress <- DownloadProgress{
|
c.downloadFailed(pack, err)
|
||||||
PercCompletion: -1,
|
|
||||||
File: pack.File,
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
defer con.Close()
|
|
||||||
|
|
||||||
var speed float64
|
|
||||||
var prevUpdate time.Time
|
|
||||||
secondsElapsed := int64(0)
|
|
||||||
totalBytes := uint64(0)
|
totalBytes := uint64(0)
|
||||||
buf := make([]byte, 0, 4*1024)
|
accBytes := uint64(0)
|
||||||
start := time.Now().UnixNano()
|
averageSpeed := float64(0)
|
||||||
|
buf := make([]byte, 4*1024)
|
||||||
|
start := time.Now()
|
||||||
|
prevUpdate := start
|
||||||
|
|
||||||
for {
|
for {
|
||||||
n, err := con.Read(buf[:cap(buf)])
|
n, err := conn.Read(buf)
|
||||||
buf = buf[:n]
|
if err != nil {
|
||||||
if n == 0 {
|
if err != io.EOF {
|
||||||
if err == nil {
|
c.downloadFailed(pack, err)
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
if err == io.EOF {
|
if n == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := file.Write(buf); err != nil {
|
if _, err := file.Write(buf[:n]); err != nil {
|
||||||
c.Progress <- DownloadProgress{
|
c.downloadFailed(pack, err)
|
||||||
PercCompletion: -1,
|
|
||||||
File: pack.File,
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cycleBytes := uint64(len(buf))
|
accBytes += uint64(n)
|
||||||
totalBytes += cycleBytes
|
totalBytes += uint64(n)
|
||||||
percentage := round2(100 * float64(totalBytes) / float64(pack.Length))
|
|
||||||
|
|
||||||
now := time.Now().UnixNano()
|
conn.Write(uint64Bytes(totalBytes))
|
||||||
secondsElapsed = (now - start) / 1e9
|
|
||||||
speed = round2(float64(totalBytes) / (float64(secondsElapsed)))
|
|
||||||
secondsToGo := round2((float64(pack.Length) - float64(totalBytes)) / speed)
|
|
||||||
|
|
||||||
con.Write(byteRead(totalBytes))
|
if dt := time.Since(prevUpdate); dt >= time.Second {
|
||||||
|
|
||||||
if time.Since(prevUpdate) >= time.Second {
|
|
||||||
prevUpdate = time.Now()
|
prevUpdate = time.Now()
|
||||||
|
|
||||||
|
speed := float64(accBytes) / dt.Seconds()
|
||||||
|
if averageSpeed == 0 {
|
||||||
|
averageSpeed = speed
|
||||||
|
} else {
|
||||||
|
averageSpeed = 0.2*speed + 0.8*averageSpeed
|
||||||
|
}
|
||||||
|
accBytes = 0
|
||||||
|
|
||||||
|
bytesRemaining := float64(pack.Length - totalBytes)
|
||||||
|
percentage := 100 * (float64(totalBytes) / float64(pack.Length))
|
||||||
|
|
||||||
c.Progress <- DownloadProgress{
|
c.Progress <- DownloadProgress{
|
||||||
Speed: humanReadableByteCount(speed, true),
|
Speed: humanReadableByteCount(averageSpeed, true),
|
||||||
PercCompletion: percentage,
|
PercCompletion: percentage,
|
||||||
BytesRemaining: humanReadableByteCount(float64(pack.Length-totalBytes), false),
|
BytesRemaining: humanReadableByteCount(bytesRemaining, false),
|
||||||
BytesCompleted: humanReadableByteCount(float64(totalBytes), false),
|
BytesCompleted: humanReadableByteCount(float64(totalBytes), false),
|
||||||
SecondsElapsed: secondsElapsed,
|
SecondsElapsed: secondsSince(start),
|
||||||
SecondsToGo: secondsToGo,
|
SecondsToGo: bytesRemaining / averageSpeed,
|
||||||
File: pack.File,
|
File: pack.File,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
con.Write(byteRead(totalBytes))
|
// TODO: is this needed?
|
||||||
|
conn.Write(uint64Bytes(totalBytes))
|
||||||
|
|
||||||
c.Progress <- DownloadProgress{
|
c.Progress <- DownloadProgress{
|
||||||
Speed: humanReadableByteCount(speed, true),
|
|
||||||
PercCompletion: 100,
|
PercCompletion: 100,
|
||||||
BytesCompleted: humanReadableByteCount(float64(totalBytes), false),
|
BytesCompleted: humanReadableByteCount(float64(totalBytes), false),
|
||||||
SecondsElapsed: secondsElapsed,
|
SecondsElapsed: secondsSince(start),
|
||||||
File: pack.File,
|
File: pack.File,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) downloadFailed(pack *DCCSend, err error) {
|
||||||
|
c.Progress <- DownloadProgress{
|
||||||
|
PercCompletion: -1,
|
||||||
|
File: pack.File,
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type DownloadProgress struct {
|
type DownloadProgress struct {
|
||||||
File string `json:"file"`
|
File string `json:"file"`
|
||||||
Error error `json:"error"`
|
Error error `json:"error"`
|
||||||
@ -167,7 +169,7 @@ func (p DownloadProgress) ToJSON() string {
|
|||||||
return string(progress)
|
return string(progress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func uint32ToIP(n int) string {
|
func intToIP(n int) string {
|
||||||
var byte1 = n & 255
|
var byte1 = n & 255
|
||||||
var byte2 = ((n >> 8) & 255)
|
var byte2 = ((n >> 8) & 255)
|
||||||
var byte3 = ((n >> 16) & 255)
|
var byte3 = ((n >> 16) & 255)
|
||||||
@ -175,14 +177,14 @@ func uint32ToIP(n int) string {
|
|||||||
return fmt.Sprintf("%d.%d.%d.%d", byte4, byte3, byte2, byte1)
|
return fmt.Sprintf("%d.%d.%d.%d", byte4, byte3, byte2, byte1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func byteRead(totalBytes uint64) []byte {
|
func uint64Bytes(i uint64) []byte {
|
||||||
b := make([]byte, 8)
|
b := make([]byte, 8)
|
||||||
binary.BigEndian.PutUint64(b, totalBytes)
|
binary.BigEndian.PutUint64(b, i)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func round2(source float64) float64 {
|
func secondsSince(t time.Time) int64 {
|
||||||
return math.Round(100*source) / 100
|
return int64(math.Round(time.Since(t).Seconds()))
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -65,20 +65,16 @@ func (i *ircHandler) run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case progress := <-i.client.Progress:
|
case progress := <-i.client.Progress:
|
||||||
if progress.PercCompletion == 100 {
|
if progress.Error != nil {
|
||||||
i.state.sendJSON("pm", Message{
|
i.sendDCCInfo("%s: Download failed (%s)", progress.File, progress.Error)
|
||||||
Server: i.client.Host,
|
} else if progress.PercCompletion == 100 {
|
||||||
From: "@dcc",
|
i.sendDCCInfo("Download finished, get it here: %s://%s/downloads/%s/%s",
|
||||||
Content: fmt.Sprintf("%s://%s/downloads/%s/%s", i.state.String("scheme"),
|
i.state.String("scheme"), i.state.String("host"), i.state.user.Username, progress.File)
|
||||||
i.state.String("host"), i.state.user.Username, progress.File),
|
} else if progress.PercCompletion == 0 {
|
||||||
})
|
i.sendDCCInfo("%s: Starting download", progress.File)
|
||||||
} else {
|
} else {
|
||||||
i.state.sendJSON("pm", Message{
|
i.sendDCCInfo("%s: %.1f%%, %s, %s remaining, %.1fs left", progress.File,
|
||||||
Server: i.client.Host,
|
progress.PercCompletion, progress.Speed, progress.BytesRemaining, progress.SecondsToGo)
|
||||||
From: "@dcc",
|
|
||||||
Content: fmt.Sprintf("%s: %.2f%% %s remaining, %.2fs left", progress.File,
|
|
||||||
progress.PercCompletion, progress.BytesRemaining, progress.SecondsToGo),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -435,6 +431,14 @@ func (i *ircHandler) log(v ...interface{}) {
|
|||||||
log.Println("[IRC]", i.state.user.ID, i.client.Host, s[:len(s)-1])
|
log.Println("[IRC]", i.state.user.ID, i.client.Host, s[:len(s)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *ircHandler) sendDCCInfo(message string, a ...interface{}) {
|
||||||
|
i.state.sendJSON("pm", Message{
|
||||||
|
Server: i.client.Host,
|
||||||
|
From: "@dcc",
|
||||||
|
Content: fmt.Sprintf(message, a...),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func parseMode(mode string) *Mode {
|
func parseMode(mode string) *Mode {
|
||||||
m := Mode{}
|
m := Mode{}
|
||||||
add := false
|
add := false
|
||||||
|
Loading…
Reference in New Issue
Block a user