Implement DCC streaming
This commit is contained in:
parent
973578bb49
commit
e33b9f05e4
15 changed files with 407 additions and 218 deletions
|
@ -26,12 +26,8 @@ type Client struct {
|
|||
// Source is the reply to SOURCE CTCP messages
|
||||
Source string
|
||||
|
||||
DownloadFolder string
|
||||
Autoget bool
|
||||
|
||||
Messages chan *Message
|
||||
ConnectionChanged chan ConnectionState
|
||||
Progress chan DownloadProgress
|
||||
Features *Features
|
||||
nick string
|
||||
channels []string
|
||||
|
@ -59,7 +55,6 @@ func NewClient(nick, username string) *Client {
|
|||
Realname: nick,
|
||||
Messages: make(chan *Message, 32),
|
||||
ConnectionChanged: make(chan ConnectionState, 4),
|
||||
Progress: make(chan DownloadProgress, 4),
|
||||
out: make(chan string, 32),
|
||||
quit: make(chan struct{}),
|
||||
reconnect: make(chan struct{}),
|
||||
|
|
|
@ -47,13 +47,6 @@ func (c *Client) handleCTCP(ctcp *CTCP, msg *Message) {
|
|||
case "CLIENTINFO":
|
||||
c.ReplyCTCP(msg.Nick, ctcp.Command, ClientInfo)
|
||||
|
||||
case "DCC":
|
||||
if strings.HasPrefix(ctcp.Params, "SEND") {
|
||||
if dccSend := ParseDCCSend(ctcp); dccSend != nil {
|
||||
go c.Download(dccSend)
|
||||
}
|
||||
}
|
||||
|
||||
case "FINGER", "VERSION":
|
||||
if c.Version != "" {
|
||||
c.ReplyCTCP(msg.Nick, ctcp.Command, c.Version)
|
||||
|
|
107
pkg/irc/dcc.go
107
pkg/irc/dcc.go
|
@ -2,14 +2,11 @@ package irc
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -52,27 +49,16 @@ func ParseDCCSend(ctcp *CTCP) *DCCSend {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Download(pack *DCCSend) {
|
||||
if !c.Autoget {
|
||||
// TODO: ask user if he/she wants to download the file
|
||||
return
|
||||
func DownloadDCC(w io.Writer, pack *DCCSend, progress chan DownloadProgress) error {
|
||||
if progress != nil {
|
||||
progress <- DownloadProgress{
|
||||
File: pack.File,
|
||||
}
|
||||
}
|
||||
|
||||
c.Progress <- DownloadProgress{
|
||||
File: pack.File,
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(filepath.Join(c.DownloadFolder, pack.File), os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
c.downloadFailed(pack, err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
conn, err := net.Dial("tcp", net.JoinHostPort(pack.IP, pack.Port))
|
||||
if err != nil {
|
||||
c.downloadFailed(pack, err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
|
@ -87,64 +73,63 @@ func (c *Client) Download(pack *DCCSend) {
|
|||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
c.downloadFailed(pack, err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := file.Write(buf[:n]); err != nil {
|
||||
c.downloadFailed(pack, err)
|
||||
return
|
||||
if _, err := w.Write(buf[:n]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accBytes += uint64(n)
|
||||
totalBytes += uint64(n)
|
||||
|
||||
conn.Write(uint64Bytes(totalBytes))
|
||||
_, err = conn.Write(uint64Bytes(totalBytes))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if dt := time.Since(prevUpdate); dt >= time.Second {
|
||||
prevUpdate = time.Now()
|
||||
if progress != nil {
|
||||
if dt := time.Since(prevUpdate); dt >= time.Second {
|
||||
prevUpdate = time.Now()
|
||||
|
||||
speed := float64(accBytes) / dt.Seconds()
|
||||
if averageSpeed == 0 {
|
||||
averageSpeed = speed
|
||||
} else {
|
||||
averageSpeed = 0.2*speed + 0.8*averageSpeed
|
||||
}
|
||||
accBytes = 0
|
||||
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))
|
||||
bytesRemaining := float64(pack.Length - totalBytes)
|
||||
percentage := 100 * (float64(totalBytes) / float64(pack.Length))
|
||||
|
||||
c.Progress <- DownloadProgress{
|
||||
Speed: humanReadableByteCount(averageSpeed, true),
|
||||
PercCompletion: percentage,
|
||||
BytesRemaining: humanReadableByteCount(bytesRemaining, false),
|
||||
BytesCompleted: humanReadableByteCount(float64(totalBytes), false),
|
||||
SecondsElapsed: secondsSince(start),
|
||||
SecondsToGo: bytesRemaining / averageSpeed,
|
||||
File: pack.File,
|
||||
progress <- DownloadProgress{
|
||||
Speed: humanReadableByteCount(averageSpeed, true),
|
||||
PercCompletion: percentage,
|
||||
BytesRemaining: humanReadableByteCount(bytesRemaining, false),
|
||||
BytesCompleted: humanReadableByteCount(float64(totalBytes), false),
|
||||
SecondsElapsed: secondsSince(start),
|
||||
SecondsToGo: bytesRemaining / averageSpeed,
|
||||
File: pack.File,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.Progress <- DownloadProgress{
|
||||
PercCompletion: 100,
|
||||
BytesCompleted: humanReadableByteCount(float64(totalBytes), false),
|
||||
SecondsElapsed: secondsSince(start),
|
||||
File: pack.File,
|
||||
if progress != nil {
|
||||
progress <- DownloadProgress{
|
||||
PercCompletion: 100,
|
||||
BytesCompleted: humanReadableByteCount(float64(totalBytes), false),
|
||||
SecondsElapsed: secondsSince(start),
|
||||
File: pack.File,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) downloadFailed(pack *DCCSend, err error) {
|
||||
c.Progress <- DownloadProgress{
|
||||
PercCompletion: -1,
|
||||
File: pack.File,
|
||||
Error: err,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DownloadProgress struct {
|
||||
|
@ -158,14 +143,6 @@ type DownloadProgress struct {
|
|||
SecondsToGo float64 `json:"eta"`
|
||||
}
|
||||
|
||||
func (p DownloadProgress) ToJSON() string {
|
||||
progress, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(progress)
|
||||
}
|
||||
|
||||
func intToIP(n int) string {
|
||||
var byte1 = n & 255
|
||||
var byte2 = ((n >> 8) & 255)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue