forked from mm1729/Bittorrent
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient.go
151 lines (130 loc) · 3.73 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package main
import (
"fmt"
"log"
"os"
"os/signal"
"runtime"
// "strings"
"sync"
"time"
)
//ClientID is the 20 byte id of our client
//ProtoName is the BitTorrent protocol we are using
const (
ListenPort = 6881
ProtoName = "BitTorrent protocol"
ClientID = "DONDESTALABIBLIOTECA"
)
var manager PeerContactManager
var killCh chan bool = make(chan bool) // used to signal kill tracker connection
func sigHandler(ch chan os.Signal, tkInfo TrackerInfo) {
<-ch
fmt.Println("Exiting...")
if err := manager.StopDownload(); err != nil {
fmt.Println(err)
}
killCh <- true // stop tracker connection
<-killCh // wait to stop tracker connection
os.Exit(0)
}
func trackerUpdater(killCh chan bool, tkInfo TrackerInfo, interval int64, iDict InfoDict) {
// keep announcing to tracker at Interval seconds
ticker := time.NewTicker(time.Second * time.Duration(interval))
sentCompleted := false
go func() {
fmt.Println("updating...")
for _ = range ticker.C {
tkInfo.Uploaded, tkInfo.Downloaded, tkInfo.Left =
manager.GetProgress()
tkInfo.sendGetRequest("")
if sentCompleted { // finished download
return
}
}
}()
for {
toKill := <-killCh
// fmt.Println("Tokill: ", toKill, " sentCompleted : ", sentCompleted)
if sentCompleted == false { // just send completed
ticker.Stop() // ticker is done
// Send event stopped message to tracker
tkInfo.Uploaded, tkInfo.Downloaded, tkInfo.Left = manager.GetProgress()
// we calculated tkInfo.Downloaded without accounting for the actual length of
// the last piece. So, if the total downloaded is some bytes < piece length
// just say it downloaded the whole thing.
if tkInfo.Downloaded-iDict.Length < iDict.PieceLength {
tkInfo.Downloaded = iDict.Length
tkInfo.Left = 0
}
if tkInfo.Left == 0 { // send completed message if the download is complete
// tkInfo.sendGetRequest("completed")
}
sentCompleted = true
}
if toKill == true { // we are done - return
tkInfo.Disconnect()
killCh <- true // finished disconnect
return
}
}
}
func main() {
runtime.GOMAXPROCS(2)
if len(os.Args) < 3 {
fmt.Println("Illegal USAGE!\n USAGE : ./Bittorrent <torrent_file> <output file>")
return
}
torrentFile := os.Args[1]
fileName := os.Args[2]
torrent, err := NewTorrent(torrentFile)
if err != nil {
log.Fatal("Unable to decode the torrent file\n", err)
}
// create a new tracker and receive the list of peers
hash := torrent.InfoHash()
iDict := torrent.InfoDict()
// Tracker connection
tkInfo := NewTracker(hash, torrent, &iDict, ListenPort)
peerList, interval := tkInfo.Connect()
fmt.Println(iDict.Length, iDict.PieceLength)
/*interval := 2
peerList := make([]Peer, 1, 1)
peerList[0].IP = "127.0.0.1"
peerList[0].PeerID = "DONDESTALABIBLIOTECA"
peerList[0].Port = 6881*/
//fmt.Printf("%v\n", peerList)
//Start peer download
tInfo := TorrentInfo{
TInfo: &iDict,
ClientID: ClientID,
ProtoName: ProtoName,
ProtoNameLen: len(ProtoName),
InfoHash: string(hash[:len(hash)]),
}
var wg sync.WaitGroup
manager = NewPeerContactManager(&tkInfo, &wg, tInfo, fileName, 10, 10, 10)
// keep announcing to tracker at Interval seconds
go trackerUpdater(killCh, tkInfo, interval, iDict)
sigChannel := make(chan os.Signal, 1)
signal.Notify(sigChannel, os.Interrupt)
go func() {
sigHandler(sigChannel, tkInfo)
}()
// start listening for requests
go func() {
if err := manager.StartIncoming(ListenPort); err != nil {
fmt.Println("Listen Error\n")
fmt.Println(err)
return
}
}()
if err := manager.StartOutgoing(peerList); err != nil {
fmt.Println(err)
return
}
killCh <- false // don't kill tracker connection but say we completed it
fmt.Println("Download completed. Waiting for user input...")
for {
}
}