Added the Files tab, fixed peer tab, started adding functionality for the buttons, cleaned up general tab

This commit is contained in:
2017-12-30 23:24:17 -05:00
parent a9315a4b54
commit 7411638c95
17 changed files with 21952 additions and 21939 deletions

View File

@@ -15,21 +15,6 @@ type Message struct {
Payload []string Payload []string
} }
//GenericPayload is for any request to the server that only requires the TorrentHashString for matching (which is a lot of requests)
type GenericPayload struct {
TorrentHashString string
}
//MagnetMessage contains the magnet link entered by the user under ADD MAGNET link on the top toolbar
type MagnetMessage struct {
MagnetLink string `json:MagnetLink`
}
//TorrentCommandMessage contains a slice of strings that has the list of torrents to be acted on.
type TorrentCommandMessage struct {
TorrentHashStrings []string
}
//Next are the messages the server sends to the client //Next are the messages the server sends to the client
//TorrentList struct contains the torrent list that is sent to the client //TorrentList struct contains the torrent list that is sent to the client
@@ -42,8 +27,8 @@ type TorrentList struct { //helps create the JSON structure that react expects t
//TorrentFileList supplies a list of files attached to a single torrent along with some additional information //TorrentFileList supplies a list of files attached to a single torrent along with some additional information
type TorrentFileList struct { type TorrentFileList struct {
MessageType string MessageType string
TotalFiles int `json:"total"` TotalFiles int `json:"TotalFiles"`
FileList []torrent.File `json:"fileList"` FileList []TorrentFile `json:"FileList"`
} }
//PeerFileList returns a slice of peers //PeerFileList returns a slice of peers
@@ -53,30 +38,40 @@ type PeerFileList struct {
PeerList []torrent.Peer `json:"PeerList"` PeerList []torrent.Peer `json:"PeerList"`
} }
//ClientDB struct contains the struct that is used to compose the torrentlist //TorrentFile describes a single file that a torrent client is downloading for a single torrent
type ClientDB struct { type TorrentFile struct {
TorrentName string `json:"TorrentName"` TorrentHashString string //Used to tie the file to a torrent //TODO not sure if neededs
DownloadedSize string `json:"DownloadedSize"` FileName string
Size string `json:"Size"` FilePath string
DownloadSpeed string `json:"DownloadSpeed"` FileSize string
downloadSpeedInt int64 FilePercent string
UploadSpeed string `json:"UploadSpeed"` FilePriority string
//UploadSpeedInt int64 }
DataBytesWritten int64
DataBytesRead int64 //ClientDB struct contains the struct that is used to compose the torrentlist
ActivePeers string `json:"ActivePeers"` type ClientDB struct { //TODO maybe seperate out the internal bits into another client struct
TorrentHashString string `json:"TorrentHashString"` TorrentHashString string `json:"TorrentHashString"` //Passed to client for displaying hash and is used to uniquly identify all torrents
PercentDone string `json:"PercentDone"` TorrentName string `json:"TorrentName"`
TorrentHash metainfo.Hash DownloadedSize string `json:"DownloadedSize"` //how much the client has downloaded total
StoragePath string `json:"StoragePath"` Size string `json:"Size"` //total size of the torrent
DateAdded string DownloadSpeed string `json:"DownloadSpeed"` //the dl speed of the torrent
KnownSwarm []torrent.Peer Status string `json:"Status"` //Passed to client for display
Status string `json:"Status"` PercentDone string `json:"PercentDone"` //Passed to client to show percent done
BytesCompleted int64 ActivePeers string `json:"ActivePeers"` //passed to client
UpdatedAt time.Time UploadSpeed string `json:"UploadSpeed"` //passed to client to show Uploadspeed
UploadRatio string StoragePath string `json:"StoragePath"` //Passed to client (and stored in stormdb)
AddedAt string DateAdded string //Passed to client (and stored in stormdb)
ETA string `json:"ETA"` ETA string `json:"ETA"` //Passed to client
Label string Label string //Passed to client and stored in stormdb
SourceType string `json:"SourceType"` SourceType string `json:"SourceType"` //Stores whether the torrent came from a torrent file or a magnet link
KnownSwarm []torrent.Peer //Passed to client for Peer Tab
UploadRatio string //Passed to client, stores the string for uploadratio stored in stormdb
TotalUploadedSize string //Humanized version of TotalUploadedBytes to pass to the client
TotalUploadedBytes int64 //includes bytes that happened before reboot (from stormdb)
downloadSpeedInt int64 //Internal used for calculating dl speed
BytesCompleted int64 //Internal used for calculating the dl speed
DataBytesWritten int64 //Internal used for calculating dl speed
DataBytesRead int64 //Internal used for calculating dl speed
UpdatedAt time.Time //Internal used for calculating speeds of upload and download
TorrentHash metainfo.Hash //Used to create string for TorrentHashString... not sure why I have it... make that a TODO I guess
} }

View File

@@ -3,12 +3,13 @@ package engine //main file for all the calculations and data gathering needed fo
import ( import (
"fmt" "fmt"
"os" "os"
"strconv"
"strings" "strings"
"time" "time"
"github.com/anacrolix/torrent" "github.com/anacrolix/torrent"
"github.com/anacrolix/torrent/metainfo" "github.com/anacrolix/torrent/metainfo"
"github.com/boltdb/bolt" "github.com/asdine/storm"
Storage "github.com/deranjer/goTorrent/storage" Storage "github.com/deranjer/goTorrent/storage"
) )
@@ -20,7 +21,7 @@ func timeOutInfo(clientTorrent *torrent.Torrent, seconds time.Duration) (deleted
}() }()
select { select {
case <-clientTorrent.GotInfo(): //attempting to retrieve info for torrent case <-clientTorrent.GotInfo(): //attempting to retrieve info for torrent
//fmt.Println("Recieved torrent info for...", clientTorrent.Name()) fmt.Println("Recieved torrent info for...", clientTorrent.Name())
clientTorrent.DownloadAll() clientTorrent.DownloadAll()
return false return false
case <-timeout: // getting info for torrent has timed out so purging the torrent case <-timeout: // getting info for torrent has timed out so purging the torrent
@@ -32,7 +33,7 @@ func timeOutInfo(clientTorrent *torrent.Torrent, seconds time.Duration) (deleted
} }
//StartTorrent creates the storage.db entry and starts A NEW TORRENT and adds to the running torrent array //StartTorrent creates the storage.db entry and starts A NEW TORRENT and adds to the running torrent array
func StartTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage *Storage.TorrentLocal, torrentDbStorage *bolt.DB, dataDir string, torrentFile string, torrentFileName string) { func StartTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage Storage.TorrentLocal, torrentDbStorage *storm.DB, dataDir string, torrentFile string, torrentFileName string) {
timeOutInfo(clientTorrent, 45) //seeing if adding the torrrent times out (giving 45 seconds) timeOutInfo(clientTorrent, 45) //seeing if adding the torrrent times out (giving 45 seconds)
var TempHash metainfo.Hash var TempHash metainfo.Hash
@@ -55,7 +56,7 @@ func StartTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage *Storage.T
} }
//CreateRunningTorrentArray creates the entire torrent list to pass to client //CreateRunningTorrentArray creates the entire torrent list to pass to client
func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Storage.TorrentLocal, PreviousTorrentArray []ClientDB, config FullClientSettings, db *bolt.DB) (RunningTorrentArray []ClientDB) { func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Storage.TorrentLocal, PreviousTorrentArray []ClientDB, config FullClientSettings, db *storm.DB) (RunningTorrentArray []ClientDB) {
for _, element := range TorrentLocalArray { //re-adding all the torrents we had stored from last shutdown or just added via file or magnet link for _, element := range TorrentLocalArray { //re-adding all the torrents we had stored from last shutdown or just added via file or magnet link
@@ -94,17 +95,12 @@ func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto
} }
} }
} }
activePeersString := fmt.Sprintf("%v", fullStruct.ActivePeers) //converting to strings activePeersString := strconv.Itoa(fullStruct.ActivePeers) //converting to strings
totalPeersString := fmt.Sprintf("%v", fullStruct.TotalPeers) totalPeersString := fmt.Sprintf("%v", fullStruct.TotalPeers)
bytesCompletedMB := float32(singleTorrent.BytesCompleted() / 1024 / 1024)
totalSizeMB := float32(singleTorrent.Length() / 1024 / 1024)
//downloadSizeString := fmt.Sprintf("%d", bytesCompletedMB)
tSize, dSize := ConvertSizetoGB(totalSizeMB, bytesCompletedMB) //convert size to GB if needed
var TempHash metainfo.Hash var TempHash metainfo.Hash
TempHash = singleTorrent.InfoHash() TempHash = singleTorrent.InfoHash()
singleTorrentStorageInfo := Storage.FetchTorrentFromStorage(db, []byte(TempHash.String())) //fetching all the info from the database singleTorrentStorageInfo := Storage.FetchTorrentFromStorage(db, TempHash.String()) //fetching all the info from the database
var torrentTypeTemp string var torrentTypeTemp string
torrentTypeTemp = singleTorrentStorageInfo.TorrentType //either "file" or "magnet" maybe more in the future torrentTypeTemp = singleTorrentStorageInfo.TorrentType //either "file" or "magnet" maybe more in the future
if torrentTypeTemp == "file" { if torrentTypeTemp == "file" {
@@ -112,16 +108,19 @@ func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto
} else { } else {
fullClientDB.SourceType = "Magnet Link" fullClientDB.SourceType = "Magnet Link"
} }
fullClientDB.StoragePath = singleTorrentStorageInfo.StoragePath //grabbed from database
fullClientDB.StoragePath = singleTorrentStorageInfo.StoragePath totalSizeHumanized := HumanizeBytes(float32(singleTorrent.BytesCompleted())) //convert size to GB if needed
downloadedSizeHumanized := HumanizeBytes(float32(singleTorrent.Length()))
fullClientDB.DownloadedSize = dSize //grabbed from torrent client
fullClientDB.Size = tSize fullClientDB.DownloadedSize = downloadedSizeHumanized
PercentDone := fmt.Sprintf("%.2f", bytesCompletedMB/totalSizeMB) fullClientDB.Size = totalSizeHumanized
PercentDone := fmt.Sprintf("%.2f", float32(singleTorrent.BytesCompleted())/float32(singleTorrent.Length()))
fullClientDB.TorrentHash = TempHash fullClientDB.TorrentHash = TempHash
fullClientDB.PercentDone = PercentDone fullClientDB.PercentDone = PercentDone
fullClientDB.DataBytesRead = fullStruct.ConnStats.DataBytesRead fullClientDB.DataBytesRead = fullStruct.ConnStats.DataBytesRead //used for calculations not passed to client calculating up/down speed
fullClientDB.DataBytesWritten = fullStruct.ConnStats.DataBytesWritten fullClientDB.DataBytesWritten = fullStruct.ConnStats.DataBytesWritten //used for calculations not passed to client calculating up/down speed
fullClientDB.ActivePeers = activePeersString + " / (" + totalPeersString + ")" fullClientDB.ActivePeers = activePeersString + " / (" + totalPeersString + ")"
fullClientDB.TorrentHashString = TempHash.String() fullClientDB.TorrentHashString = TempHash.String()
fullClientDB.StoragePath = element.StoragePath fullClientDB.StoragePath = element.StoragePath
@@ -130,21 +129,21 @@ func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto
fullClientDB.BytesCompleted = singleTorrent.BytesCompleted() fullClientDB.BytesCompleted = singleTorrent.BytesCompleted()
CalculateTorrentETA(singleTorrent, fullClientDB) //calculating the ETA for the torrent CalculateTorrentETA(singleTorrent, fullClientDB) //calculating the ETA for the torrent
fullClientDB.UploadRatio = CalculateUploadRatio(singleTorrent, fullClientDB, db) //calculate the upload ratio fullClientDB.TotalUploadedBytes = singleTorrentStorageInfo.UploadedBytes
fullClientDB.TotalUploadedSize = HumanizeBytes(float32(fullClientDB.TotalUploadedBytes))
fullClientDB.UploadRatio = CalculateUploadRatio(singleTorrent, fullClientDB) //calculate the upload ratio
tickUpdateStruct := Storage.TorrentLocal{} //we are shoving the tick updates into a torrentlocal struct to pass to storage tickUpdateStruct := Storage.TorrentLocal{} //we are shoving the tick updates into a torrentlocal struct to pass to storage
tickUpdateStruct.UploadRatio = fullClientDB.UploadRatio tickUpdateStruct.UploadRatio = fullClientDB.UploadRatio
tickUpdateStruct.UploadedBytes = fullClientDB.DataBytesWritten tickUpdateStruct.UploadedBytes = fullClientDB.DataBytesWritten
tickUpdateStruct.Hash = fullClientDB.TorrentHashString
tickUpdateStruct.Hash = fullClientDB.TorrentHashString //needed for index
Storage.UpdateStorageTick(db, tickUpdateStruct) Storage.UpdateStorageTick(db, tickUpdateStruct)
//fmt.Println("Download Speed: ", fullClientDB.DownloadSpeed)
//fmt.Println("Percent Done: ", fullClientDB.PercentDone)
//tclient.WriteStatus(os.Stdout)
CalculateTorrentStatus(singleTorrent, fullClientDB) //calculate the status of the torrent, ie downloading seeding etc CalculateTorrentStatus(singleTorrent, fullClientDB) //calculate the status of the torrent, ie downloading seeding etc
RunningTorrentArray = append(RunningTorrentArray, *fullClientDB) RunningTorrentArray = append(RunningTorrentArray, *fullClientDB)
} }
//fmt.Println("RunningTorrentArrayCreated...")
return RunningTorrentArray return RunningTorrentArray
} }
@@ -152,12 +151,23 @@ func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto
func CreateFileListArray(tclient *torrent.Client, selectedHash string) TorrentFileList { func CreateFileListArray(tclient *torrent.Client, selectedHash string) TorrentFileList {
runningTorrents := tclient.Torrents() //don't need running torrent array since we aren't adding or deleting from storage runningTorrents := tclient.Torrents() //don't need running torrent array since we aren't adding or deleting from storage
TorrentFileListSelected := TorrentFileList{} TorrentFileListSelected := TorrentFileList{}
TorrentFileStruct := TorrentFile{}
for _, singleTorrent := range runningTorrents { for _, singleTorrent := range runningTorrents {
tempHash := singleTorrent.InfoHash().String() tempHash := singleTorrent.InfoHash().String()
if tempHash == selectedHash { // if our selection hash equals our torrent hash if tempHash == selectedHash { // if our selection hash equals our torrent hash
TorrentFileListSelected.FileList = singleTorrent.Files() torrentFilesRaw := singleTorrent.Files()
for _, singleFile := range torrentFilesRaw {
TorrentFileStruct.TorrentHashString = tempHash
TorrentFileStruct.FileName = singleFile.DisplayPath()
TorrentFileStruct.FilePath = singleFile.Path()
TorrentFileStruct.FilePercent = fmt.Sprintf("%.2f", float32(singleFile.Length())/float32(singleFile.Length())) //TODO figure out downloaded size of file
TorrentFileStruct.FilePriority = "Normal" //TODO, figure out how to store this per file in storage and also tie a priority to a file
TorrentFileStruct.FileSize = HumanizeBytes(float32(singleFile.Length()))
TorrentFileListSelected.FileList = append(TorrentFileListSelected.FileList, TorrentFileStruct)
}
TorrentFileListSelected.MessageType = "torrentFileList" TorrentFileListSelected.MessageType = "torrentFileList"
TorrentFileListSelected.TotalFiles = len(singleTorrent.Files()) TorrentFileListSelected.TotalFiles = len(singleTorrent.Files())
fmt.Println("filelist", TorrentFileListSelected)
return TorrentFileListSelected return TorrentFileListSelected
} }
@@ -183,9 +193,9 @@ func CreatePeerListArray(tclient *torrent.Client, selectedHash string) PeerFileL
} }
//CreateTorrentDetailJSON creates the json response for a request for more torrent information //CreateTorrentDetailJSON creates the json response for a request for more torrent information
func CreateTorrentDetailJSON(tclient *torrent.Client, selectedHash string, torrentStorage *bolt.DB) ClientDB { func CreateTorrentDetailJSON(tclient *torrent.Client, selectedHash string, torrentStorage *storm.DB) ClientDB {
localTorrentInfo := Storage.FetchTorrentFromStorage(torrentStorage, []byte(selectedHash)) localTorrentInfo := Storage.FetchTorrentFromStorage(torrentStorage, selectedHash)
runningTorrents := tclient.Torrents() runningTorrents := tclient.Torrents()

View File

@@ -5,7 +5,6 @@ import (
"time" "time"
"github.com/anacrolix/torrent" "github.com/anacrolix/torrent"
"github.com/boltdb/bolt"
) )
func secondsToMinutes(inSeconds int64) string { func secondsToMinutes(inSeconds int64) string {
@@ -17,34 +16,22 @@ func secondsToMinutes(inSeconds int64) string {
return str return str
} }
//ConvertSizetoGB changes the sizes //HumanizeBytes returns a nice humanized version of bytes in either GB or MB
func ConvertSizetoGB(t float32, d float32) (tDelta string, dDelta string) { //converting sizes to MB or GB as needed and adding string func HumanizeBytes(bytes float32) string {
if t > 1024 && d > 1024 { if bytes < 1000000 { //if we have less than 1MB in bytes convert to KB
t := fmt.Sprintf("%.2f", t/1024) pBytes := fmt.Sprintf("%.2f", bytes/1024)
t = t + " GB" pBytes = pBytes + " KB"
d := fmt.Sprintf("%.2f", d/1024) return pBytes
d = d + " GB"
return t, d
} else if d > 1024 || t > 1024 {
if d > 1024 {
d := fmt.Sprintf("%.2f", d/1024)
d = d + " GB"
t := fmt.Sprintf("%.2f", t)
t = t + " MB"
return t, d
} }
d := fmt.Sprintf("%.2f", d) bytes = bytes / 1024 / 1024 //Converting bytes to a useful measure
d = d + " MB" if bytes > 1024 {
t := fmt.Sprintf("%.2f", t/1024) pBytes := fmt.Sprintf("%.2f", bytes/1024)
t = t + " GB" pBytes = pBytes + " GB"
return t, d return pBytes
} else {
d := fmt.Sprintf("%.2f", d)
t := fmt.Sprintf("%.2f", t)
t = t + " MB"
d = d + " MB"
return t, d
} }
pBytes := fmt.Sprintf("%.2f", bytes) //If not too big or too small leave it as MB
pBytes = pBytes + " MB"
return pBytes
} }
//CalculateTorrentSpeed is used to calculate the torrent upload and download speed over time c is current clientdb, oc is last client db to calculate speed over time //CalculateTorrentSpeed is used to calculate the torrent upload and download speed over time c is current clientdb, oc is last client db to calculate speed over time
@@ -56,9 +43,6 @@ func CalculateTorrentSpeed(t *torrent.Torrent, c *ClientDB, oc ClientDB) {
db := float32(bytes - oc.BytesCompleted) //getting the delta bytes db := float32(bytes - oc.BytesCompleted) //getting the delta bytes
rate := db * (float32(time.Second) / dt) // converting into seconds rate := db * (float32(time.Second) / dt) // converting into seconds
dbU := float32(bytesUpload - oc.DataBytesWritten) dbU := float32(bytesUpload - oc.DataBytesWritten)
//fmt.Println("BytesWritten", bytesUpload)
//fmt.Println("WireBytes", t.Stats().DataBytesWritten)
//fmt.Println("ChunksWritten", t.Stats().ChunksWritten)
rateUpload := dbU * (float32(time.Second) / dt) rateUpload := dbU * (float32(time.Second) / dt)
if rate >= 0 { if rate >= 0 {
rate = rate / 1024 / 1024 //creating integer to calculate ETA rate = rate / 1024 / 1024 //creating integer to calculate ETA
@@ -90,18 +74,18 @@ func CalculateTorrentETA(t *torrent.Torrent, c *ClientDB) {
} }
} }
func CalculateUploadRatio(t *torrent.Torrent, c *ClientDB, db *bolt.DB) string { //CalculateUploadRatio calculates the download to upload ratio so you can see if you are being a good seeder
if c.DataBytesWritten > 0 { func CalculateUploadRatio(t *torrent.Torrent, c *ClientDB) string {
uploadRatioTemp := c.DataBytesRead / c.DataBytesWritten if c.TotalUploadedBytes > 0 && t.BytesCompleted() > 0 { //If we have actually started uploading and downloading stuff start calculating our ratio
uploadRatio := fmt.Sprintf("%.2f", uploadRatioTemp) uploadRatio := fmt.Sprintf("%.2f", float64(c.TotalUploadedBytes)/float64(t.BytesCompleted()))
return uploadRatio return uploadRatio
} }
uploadRatio := fmt.Sprintf("%.2f", 0.00) //we haven't uploaded anything so no upload ratio uploadRatio := "0.00" //we haven't uploaded anything so no upload ratio just pass a string directly
return uploadRatio return uploadRatio
} }
//CalculateTorrentStatus is used to determine what the STATUS column of the frontend will display ll2 //CalculateTorrentStatus is used to determine what the STATUS column of the frontend will display ll2
func CalculateTorrentStatus(t *torrent.Torrent, c *ClientDB) { func CalculateTorrentStatus(t *torrent.Torrent, c *ClientDB) { //TODO redo all of this to allow for stopped torrents
if t.Seeding() && t.Stats().ActivePeers > 0 && t.BytesMissing() == 0 { if t.Seeding() && t.Stats().ActivePeers > 0 && t.BytesMissing() == 0 {
c.Status = "Seeding" c.Status = "Seeding"
} else if t.Stats().ActivePeers > 0 && t.BytesMissing() > 0 { } else if t.Stats().ActivePeers > 0 && t.BytesMissing() > 0 {

25
main.go
View File

@@ -12,7 +12,8 @@ import (
"path/filepath" "path/filepath"
"github.com/anacrolix/torrent" "github.com/anacrolix/torrent"
"github.com/boltdb/bolt" "github.com/asdine/storm"
//"github.com/boltdb/bolt"
Engine "github.com/deranjer/goTorrent/engine" Engine "github.com/deranjer/goTorrent/engine"
Storage "github.com/deranjer/goTorrent/storage" Storage "github.com/deranjer/goTorrent/storage"
"github.com/gorilla/mux" "github.com/gorilla/mux"
@@ -45,16 +46,16 @@ func main() {
//setting up the torrent client //setting up the torrent client
Config := Engine.FullClientSettingsNew() //grabbing from settings.go Config := Engine.FullClientSettingsNew() //grabbing from settings.go
os.Mkdir(Config.TFileUploadFolder, os.ModeDir) //creating a directory to store uploaded torrent files os.Mkdir(Config.TFileUploadFolder, os.ModeDir) //creating a directory to store uploaded torrent files
torrentLocalStorage := new(Storage.TorrentLocal) //creating a new struct that stores all of our local storage info torrentLocalStorage := Storage.TorrentLocal{} //creating a new struct that stores all of our local storage info
fmt.Printf("%+v\n", Config) //fmt.Printf("%+v\n", Config)
tclient, err := torrent.NewClient(&Config.Config) //pulling out the torrent specific config to use tclient, err := torrent.NewClient(&Config.Config) //pulling out the torrent specific config to use
if err != nil { if err != nil {
log.Fatalf("error creating client: %s", err) log.Fatalf("error creating client: %s", err)
} }
db, err := bolt.Open("storage.db", 0600, nil) //initializing the boltDB store that contains all the added torrents db, err := storm.Open("storage.db") //initializing the boltDB store that contains all the added torrents
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@@ -128,11 +129,11 @@ func main() {
fmt.Println("Unable to read JSON client message", err) fmt.Println("Unable to read JSON client message", err)
} }
//fmt.Println("MessageFull", msg) fmt.Println("MessageFull", msg)
switch msg.MessageType { //first handling data requests switch msg.MessageType { //first handling data requests
case "torrentListRequest": case "torrentListRequest":
fmt.Println("client Requested TorrentList Update") //fmt.Println("client Requested TorrentList Update")
TorrentLocalArray = Storage.ReadInTorrents(db) TorrentLocalArray = Storage.ReadInTorrents(db)
RunningTorrentArray = Engine.CreateRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db) //Updates the RunningTorrentArray with the current client data as well RunningTorrentArray = Engine.CreateRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db) //Updates the RunningTorrentArray with the current client data as well
PreviousTorrentArray = RunningTorrentArray PreviousTorrentArray = RunningTorrentArray
@@ -150,6 +151,7 @@ func main() {
fmt.Println("client Requested Filelist update") fmt.Println("client Requested Filelist update")
FileListArray := Engine.CreateFileListArray(tclient, msg.Payload[0]) FileListArray := Engine.CreateFileListArray(tclient, msg.Payload[0])
conn.WriteJSON(FileListArray) //writing the JSON to the client conn.WriteJSON(FileListArray) //writing the JSON to the client
break break
case "torrentDetailedInfo": //TODO Figure out how to get single torrent info correctly case "torrentDetailedInfo": //TODO Figure out how to get single torrent info correctly
@@ -170,9 +172,7 @@ func main() {
break break
case "magnetLinkSubmit": //if we detect a magnet link we will be adding a magnet torrent case "magnetLinkSubmit": //if we detect a magnet link we will be adding a magnet torrent
magnetMessage := Engine.MagnetMessage{} //grabbing a magnetMessage struct from engine->clientstructs clientTorrent, err := tclient.AddMagnet(msg.Payload[0]) //reading the payload into the torrent client
json.Unmarshal([]byte(msg.Payload[0]), &magnetMessage) //unmarshalling the "Payload" from Message into our magnetmessage struct
clientTorrent, err := tclient.AddMagnet(magnetMessage.MagnetLink) //reading the payload into the torrent client
if err != nil { if err != nil {
fmt.Println("Magnet Error", err) fmt.Println("Magnet Error", err)
} }
@@ -183,13 +183,13 @@ func main() {
break break
case "stopTorrents": case "stopTorrents":
TorrentListCommands := Engine.TorrentCommandMessage{} TorrentListCommands := msg.Payload
for _, singleTorrent := range runningTorrents { for _, singleTorrent := range runningTorrents {
for _, singleSelection := range TorrentListCommands.TorrentHashStrings { for _, singleSelection := range TorrentListCommands {
if singleTorrent.InfoHash().String() == singleSelection { if singleTorrent.InfoHash().String() == singleSelection {
fmt.Println("Matched for stopping torrents") fmt.Println("Matched for stopping torrents")
//singleTorrent.Drop() singleTorrent.SetMaxEstablishedConns(0) //Forcing the max amount of connections allowed to zero effectively stopping it
} }
} }
} }
@@ -202,6 +202,7 @@ func main() {
if singleTorrent.InfoHash().String() == singleSelection { if singleTorrent.InfoHash().String() == singleSelection {
fmt.Println("Matched for deleting torrents") fmt.Println("Matched for deleting torrents")
singleTorrent.Drop() singleTorrent.Drop()
//Storage.DelTorrentLocalStorage(db)
} }
} }
} }

File diff suppressed because it is too large Load Diff

BIN
storage - Copy.db Normal file

Binary file not shown.

View File

@@ -1,17 +1,14 @@
package storage package storage
import ( import (
binary "encoding/binary"
"fmt" "fmt"
"time"
"github.com/boltdb/bolt" "github.com/asdine/storm"
) )
//TODO, this entire file need to be rewritten to encode and decode from the struct //TorrentLocal is local storage of the torrents for readd on server restart, marshalled into the database using Storm
//TorrentLocal is local storage of the torrents for readd on server restart
type TorrentLocal struct { type TorrentLocal struct {
Hash string Hash string `storm:"id,unique"` //Hash should be unique for every torrent... if not we are re-adding an already added torrent \\TODO check for re-add of same torrent
DateAdded string DateAdded string
StoragePath string StoragePath string
TorrentName string TorrentName string
@@ -25,204 +22,56 @@ type TorrentLocal struct {
} }
//ReadInTorrents is called to read in ALL local stored torrents in the boltdb database (called on server restart) //ReadInTorrents is called to read in ALL local stored torrents in the boltdb database (called on server restart)
func ReadInTorrents(torrentStorage *bolt.DB) (torrentLocalArray []*TorrentLocal) { //test func ReadInTorrents(torrentStorage *storm.DB) (torrentLocalArray []*TorrentLocal) {
err := torrentStorage.Init(&TorrentLocal{}) //initializing buckets and indexes since this function runs on start
if err != nil {
fmt.Println("Error initializing and indexing database....", err)
}
torrentLocalArray = []*TorrentLocal{} //creating the array of the torrentlocal struct
torrentLocalArray = []*TorrentLocal{} err = torrentStorage.All(&torrentLocalArray) //unmarshalling the database into the []torrentlocal
if err != nil {
torrentStorage.View(func(tx *bolt.Tx) error { fmt.Println("Error reading database into torrentLocalArray", err)
tx.ForEach(func(name []byte, b *bolt.Bucket) error {
torrentLocal := new(TorrentLocal) //create a struct to store to an array //TODO clean this the fuck up just read the struct into something that converts them all the byte arrays
var Dateadded []byte
var StoragePath []byte
var Hash []byte
var TorrentName []byte
var TorrentStatus []byte
var TorrentType []byte
var TorrentFileName []byte
Dateadded = b.Get([]byte("Date"))
if Dateadded == nil {
fmt.Println("Date added error!")
Dateadded = []byte(time.Now().Format("Jan _2 2006"))
} }
StoragePath = b.Get([]byte("StoragePath"))
if StoragePath == nil {
fmt.Println("StoragePath error!")
StoragePath = []byte("downloads")
}
Hash = b.Get([]byte("InfoHash"))
if Hash == nil {
fmt.Println("Hash error!")
}
TorrentName = b.Get([]byte("TorrentName"))
if TorrentName == nil {
fmt.Println("Torrent Name not found")
TorrentName = []byte("Not Found!")
}
TorrentStatus = b.Get([]byte("TorrentStatus"))
if TorrentStatus == nil {
//fmt.Println("Torrent Status not found in local storage")
TorrentStatus = []byte("")
}
TorrentType = b.Get([]byte("TorrentType"))
if TorrentType == nil {
fmt.Println("Torrent Type not found in local storage")
TorrentStatus = []byte("")
}
TorrentFileName = b.Get([]byte("TorrentFileName"))
if TorrentFileName == nil {
fmt.Println("Torrent File Name not found in local storage")
TorrentFileName = []byte("")
}
torrentLocal.DateAdded = string(Dateadded)
torrentLocal.StoragePath = string(StoragePath)
torrentLocal.Hash = string(Hash) //Converting the byte slice back into the full hash
torrentLocal.TorrentName = string(TorrentName)
torrentLocal.TorrentStatus = string(TorrentStatus)
torrentLocal.TorrentType = string(TorrentType)
torrentLocal.TorrentFileName = string(TorrentFileName)
//fmt.Println("Torrentlocal list: ", torrentLocal)
torrentLocalArray = append(torrentLocalArray, torrentLocal) //dumping it into the array
return nil
})
return nil
})
return torrentLocalArray //all done, return the entire Array to add to the torrent client return torrentLocalArray //all done, return the entire Array to add to the torrent client
} }
//AddTorrentLocalStorage is called when adding a new torrent via any method, requires the boltdb pointer and the torrentlocal struct //AddTorrentLocalStorage is called when adding a new torrent via any method, requires the boltdb pointer and the torrentlocal struct
func AddTorrentLocalStorage(torrentStorage *bolt.DB, local *TorrentLocal) { func AddTorrentLocalStorage(torrentStorage *storm.DB, local TorrentLocal) {
println("Adding Local storage information") println("Adding Local storage information")
torrentStorage.Update(func(tx *bolt.Tx) error { err := torrentStorage.Save(&local)
b, err := tx.CreateBucketIfNotExists([]byte(local.Hash)) //translating hash into bytes for storage
if err != nil { if err != nil {
return fmt.Errorf("create bucket %s", err) fmt.Println("Error adding new Torrent to database", err)
} }
err = b.Put([]byte("Date"), []byte(local.DateAdded)) //TODO error checking marshall into JSON
if err != nil {
return err
}
err = b.Put([]byte("StoragePath"), []byte(local.StoragePath))
if err != nil {
return err
}
err = b.Put([]byte("InfoHash"), []byte(local.Hash))
if err != nil {
return err
}
err = b.Put([]byte("TorrentName"), []byte(local.TorrentName))
if err != nil {
return err
}
err = b.Put([]byte("TorrentType"), []byte(local.TorrentType))
if err != nil {
return err
}
err = b.Put([]byte("TorrentFileName"), []byte(local.TorrentFileName))
if err != nil {
return err
}
err = b.Put([]byte("UploadRatio"), []byte(local.UploadRatio))
if err != nil {
return err
}
return nil
})
} }
//DelTorrentLocalStorage is called to delete a torrent when we fail (for whatever reason to load the information for it). Deleted by HASH matching. //DelTorrentLocalStorage is called to delete a torrent when we fail (for whatever reason to load the information for it). Deleted by HASH matching.
func DelTorrentLocalStorage(torrentStorage *bolt.DB, local *TorrentLocal) { func DelTorrentLocalStorage(torrentStorage *storm.DB, local *TorrentLocal) { //TODO do a ONE and purge the torrent that way
println("Deleting torrent", local.TorrentFileName) println("Deleting torrent", local.TorrentFileName)
err := torrentStorage.DeleteStruct(&local)
torrentStorage.Update(func(tx *bolt.Tx) error {
err := tx.DeleteBucket([]byte(local.Hash))
if err != nil { if err != nil {
return err fmt.Println("Error deleting torrent from database", err)
} }
return nil
})
} }
//UpdateStorageTick updates the values in boltdb that should update on every tick (like uploadratio or uploadedbytes, not downloaded since we should have the actual file) //UpdateStorageTick updates the values in boltdb that should update on every tick (like uploadratio or uploadedbytes, not downloaded since we should have the actual file)
func UpdateStorageTick(torrentStorage *bolt.DB, torrentLocal TorrentLocal) { func UpdateStorageTick(torrentStorage *storm.DB, torrentLocal TorrentLocal) {
UploadedBytes := make([]byte, 8) err := torrentStorage.Update(&torrentLocal)
binary.LittleEndian.PutUint64(UploadedBytes, uint64(torrentLocal.UploadedBytes)) //converting int64 into byte slice for storage
selectedHash := []byte(torrentLocal.Hash)
torrentStorage.Update(func(tx *bolt.Tx) error {
b := tx.Bucket(selectedHash)
err := b.Put([]byte("UploadRatio"), []byte(torrentLocal.UploadRatio))
if err != nil { if err != nil {
return err fmt.Println("Error performing tick update to database", err)
} }
err = b.Put([]byte("UploadedBytes"), []byte(UploadedBytes))
if err != nil {
return err
}
return nil
})
} }
//FetchTorrentFromStorage grabs the localtorrent info from the bolt database for usage found by torrenthash //FetchTorrentFromStorage grabs the localtorrent info from the bolt database for usage found by torrenthash
func FetchTorrentFromStorage(torrentStorage *bolt.DB, selectedHash []byte) TorrentLocal { func FetchTorrentFromStorage(torrentStorage *storm.DB, selectedHash string) TorrentLocal {
singleTorrentInfo := TorrentLocal{} singleTorrentInfo := TorrentLocal{}
torrentStorage.View(func(tx *bolt.Tx) error { err := torrentStorage.One("Hash", selectedHash, &singleTorrentInfo)
b := tx.Bucket(selectedHash) if err != nil {
var Dateadded []byte fmt.Println("Failure selecting single torrent!", err)
var StoragePath []byte
var Hash []byte
var TorrentName []byte
var TorrentStatus []byte
var TorrentType []byte
var TorrentFileName []byte
Dateadded = b.Get([]byte("Date"))
if Dateadded == nil {
fmt.Println("Date added error!")
Dateadded = []byte(time.Now().Format("Jan _2 2006"))
}
StoragePath = b.Get([]byte("StoragePath"))
if StoragePath == nil {
fmt.Println("StoragePath error!")
StoragePath = []byte("downloads")
}
Hash = b.Get([]byte("InfoHash"))
if Hash == nil {
fmt.Println("Hash error!")
}
TorrentName = b.Get([]byte("TorrentName"))
if TorrentName == nil {
fmt.Println("Torrent Name not found")
TorrentName = []byte("Not Found!")
}
TorrentStatus = b.Get([]byte("TorrentStatus"))
if TorrentStatus == nil {
//fmt.Println("Torrent Status not found in local storage")
TorrentStatus = []byte("")
}
TorrentType = b.Get([]byte("TorrentType"))
if TorrentType == nil {
fmt.Println("Torrent Type not found in local storage")
TorrentStatus = []byte("")
}
TorrentFileName = b.Get([]byte("TorrentFileName"))
if TorrentFileName == nil {
fmt.Println("Torrent File Name not found in local storage")
TorrentFileName = []byte("")
} }
singleTorrentInfo.DateAdded = string(Dateadded)
singleTorrentInfo.StoragePath = string(StoragePath)
singleTorrentInfo.Hash = string(Hash) //Converting the byte slice back into the full hash
singleTorrentInfo.TorrentName = string(TorrentName)
singleTorrentInfo.TorrentStatus = string(TorrentStatus)
singleTorrentInfo.TorrentType = string(TorrentType)
singleTorrentInfo.TorrentFileName = string(TorrentFileName)
return nil
})
return singleTorrentInfo return singleTorrentInfo
} }

View File

@@ -12,6 +12,7 @@ import Select from 'material-ui/Select/Select';
var title = document.title; //Set the number of active torrents in the title var title = document.title; //Set the number of active torrents in the title
let torrents= []; let torrents= [];
let peerList = []; let peerList = [];
let fileList = [];
var torrentListRequest = { var torrentListRequest = {
messageType: "torrentListRequest" messageType: "torrentListRequest"
@@ -23,7 +24,7 @@ var torrentListRequest = {
//websocket is started in kickwebsocket.js and is picked up here so "ws" is already defined 22 //websocket is started in kickwebsocket.js and is picked up here so "ws" is already defined 22
ws.onmessage = function (evt) { //When we recieve a message from the websocket ws.onmessage = function (evt) { //When we recieve a message from the websocket
var serverMessage = JSON.parse(evt.data) var serverMessage = JSON.parse(evt.data)
//console.log("message", serverMessage.MessageType) console.log("message", serverMessage.MessageType)
switch (serverMessage.MessageType) { switch (serverMessage.MessageType) {
case "torrentList": case "torrentList":
@@ -42,11 +43,13 @@ ws.onmessage = function (evt) { //When we recieve a message from the websocket
PercentDone: serverMessage.data[i].PercentDone, PercentDone: serverMessage.data[i].PercentDone,
StoragePath: serverMessage.data[i].StoragePath, StoragePath: serverMessage.data[i].StoragePath,
DateAdded: serverMessage.data[i].DateAdded, DateAdded: serverMessage.data[i].DateAdded,
SourceType: serverMessage.data[i].SourceType,
Status: serverMessage.data[i].Status, Status: serverMessage.data[i].Status,
BytesCompleted: serverMessage.data[i].BytesCompleted, BytesCompleted: serverMessage.data[i].BytesCompleted,
ActivePeers: serverMessage.data[i].ActivePeers, ActivePeers: serverMessage.data[i].ActivePeers,
ETA: serverMessage.data[i].ETA, ETA: serverMessage.data[i].ETA,
Ratio: serverMessage.data[i].Ratio, TotalUploadedSize: serverMessage.data[i].TotalUploadedSize,
Ratio: serverMessage.data[i].UploadRatio,
}) })
} }
var newTitle = '(' + serverMessage.total + ')' + title; //updating the title var newTitle = '(' + serverMessage.total + ')' + title; //updating the title
@@ -70,16 +73,18 @@ ws.onmessage = function (evt) { //When we recieve a message from the websocket
break break
case "torrentFileList": case "torrentFileList":
console.log("Recieved FileListUpdate", serverMessage.fileList) console.log("Recieved FileListUpdate", evt.data)
fileList = []; fileList = [];
for (var i = 0; i < serverMessage.total; i++){ for (var i = 0; i < serverMessage.TotalFiles; i++){
fileList.push({ fileList.push({
fileList: serverMessage.fileList[i] FileName: serverMessage.FileList[i].FileName,
FilePath: serverMessage.FileList[i].FilePath,
FileSize: serverMessage.FileList[i].FileSize,
FilePercent: serverMessage.FileList[i].FilePercent,
FilePriority: serverMessage.FileList[i].FilePriority,
}) })
} }
console.log("filelist", fileList)
break break
case "speedTab": case "speedTab":
@@ -123,11 +128,16 @@ class BackendSocket extends React.Component {
MessageType: "torrentPeerListRequest", MessageType: "torrentPeerListRequest",
Payload: selectionHashes, Payload: selectionHashes,
} }
//console.log("Peers tab information requested", peerListHashes) console.log("Peers tab information requested", peerListHashes)
ws.send(JSON.stringify(peerListHashes)) ws.send(JSON.stringify(peerListHashes))
break; break;
case 2: case 2:
console.log("Files tab information requested") let fileListHashes = {
MessageType: "torrentFileListRequest",
Payload: selectionHashes,
}
console.log("Files tab information requested", fileListHashes)
ws.send(JSON.stringify(fileListHashes))
break; break;
case 3: case 3:
console.log("Speed tab information requested") console.log("Speed tab information requested")
@@ -166,13 +176,28 @@ class BackendSocket extends React.Component {
ws.send(JSON.stringify(torrentListRequest))//talking to the server to get the torrent list ws.send(JSON.stringify(torrentListRequest))//talking to the server to get the torrent list
console.log("Torrentlist", torrents) console.log("Torrentlist", torrents)
this.props.newTorrentList(torrents) //sending the list of torrents to torrentlist.js this.props.newTorrentList(torrents) //sending the list of torrents to torrentlist.js
if (this.props.selectedTab === 1 && this.props.selectionHashes.length === 1){ //if we are on the peerlist tab dispatch a new peerlist if (this.props.selectionHashes.length === 1){
switch(this.props.selectedTab){
case 1:
let peerListHashes = { let peerListHashes = {
MessageType: "torrentPeerListRequest", MessageType: "torrentPeerListRequest",
Payload: this.props.selectionHashes, Payload: this.props.selectionHashes,
} }
ws.send(JSON.stringify(peerListHashes)) ws.send(JSON.stringify(peerListHashes))
this.props.newPeerList(peerList) this.props.newPeerList(peerList)
break;
case 2:
let fileListHashes = {
MessageType: "torrentFileListRequest",
Payload: this.props.selectionHashes,
}
console.log("Files tab information requested", fileList)
ws.send(JSON.stringify(fileListHashes))
this.props.newFileList(fileList)
break;
}
} }
} }
@@ -213,7 +238,8 @@ const mapStateToProps = state => {
const mapDispatchToProps = dispatch => { const mapDispatchToProps = dispatch => {
return { return {
newTorrentList: (torrentList) => dispatch({type: actionTypes.TORRENT_LIST, torrentList }), newTorrentList: (torrentList) => dispatch({type: actionTypes.TORRENT_LIST, torrentList }),
newPeerList: (peerList) => dispatch({type: actionTypes.PEER_LIST, peerList}) newPeerList: (peerList) => dispatch({type: actionTypes.PEER_LIST, peerList}),
newFileList: (fileList) => dispatch({type: actionTypes.FILE_LIST, fileList}),
} }
} }

View File

@@ -0,0 +1,69 @@
import React from 'react';
import ReactDOM from 'react-dom';
import {BootstrapTable, TableHeaderColumn} from 'react-bootstrap-table';
import {
SortingState, LocalSorting, VirtualTableLayout, SelectionState,
} from '@devexpress/dx-react-grid';
import {
Grid, TableView, TableHeaderRow, PagingPanel, VirtualTableView, TableColumnResizing,
DragDropContext, TableColumnReordering,
} from '@devexpress/dx-react-grid-material-ui';
import {connect} from 'react-redux';
import * as actionTypes from '../../store/actions';
class FileTab extends React.Component {
constructor(props) {
super(props);
this.state = { //rows are stored in redux they are sent over from the server
columns: [
{ name: 'FileName', title: 'File Name'},
{ name: 'FilePath', title: 'File Path' },
{ name: 'FileSize', title: 'File Size'},
//{ name: 'Country', title: 'Country of Origin'}, //TODO map IP to country
{ name: 'FilePercent', title: 'File Percent'},
{ name: 'FilePriority', title: 'File Priority'}, //T=Tracker, I=Incoming, Hg=DHTGetPeers, Ha=DHTAnnouncePeer, X=PEX
],
sorting: [],
columnOrder: ['FileName', 'FilePath', 'FileSize', 'FilePercent', 'FilePriority'],
columnWidths: {FileName: 250, FilePath: 450, FileSize: 100, FilePercent: 100, FilePriority: 75},
};
this.changeColumnOrder = columnOrder => this.setState({columnOrder});
this.changeColumnWidths = columnWidths => this.setState({columnWidths});
this.changeSorting = sorting => this.setState({sorting});
}
render() {
return (
<Grid rows={this.props.fileList} columns={this.state.columns}>
<SortingState sorting={this.state.sorting} onSortingChange={this.changeSorting} />
<LocalSorting />
<DragDropContext />
<TableView />
<TableColumnResizing columnWidths={this.state.columnWidths} onColumnWidthsChange={this.changeColumnWidths}/>
<TableColumnReordering order={this.state.columnOrder} onOrderChange={this.changeColumnOrder} />
<TableHeaderRow allowSorting allowResizing allowDragging />
</Grid>
);
}
}
const mapStateToProps = state => {
return {
selectionHashes: state.selectionHashes,
fileList: state.fileList,
};
}
export default connect(mapStateToProps)(FileTab)

View File

@@ -64,7 +64,7 @@ class GeneralTab extends React.Component {
<Paper className={classes.paper}>Storage Path: <span className={classes.floatRight}>{this.state.selectedTorrent["StoragePath"]} </span> </Paper> <Paper className={classes.paper}>Storage Path: <span className={classes.floatRight}>{this.state.selectedTorrent["StoragePath"]} </span> </Paper>
<Paper className={classes.paper}>Date Added: <span className={classes.floatRight}> {this.state.selectedTorrent["DateAdded"]} </span> </Paper> <Paper className={classes.paper}>Date Added: <span className={classes.floatRight}> {this.state.selectedTorrent["DateAdded"]} </span> </Paper>
<Paper className={classes.paper}>Source Type: <span className={classes.floatRight}> {this.state.selectedTorrent["SourceType"]} </span> </Paper> <Paper className={classes.paper}>Source Type: <span className={classes.floatRight}> {this.state.selectedTorrent["SourceType"]} </span> </Paper>
<Paper className={classes.paper}>Label: <span className={classes.floatRight}> {this.state.selectedTorrent["Status"]} </span> </Paper> <Paper className={classes.paper}>Label: <span className={classes.floatRight}> None </span> </Paper>
<Paper className={classes.paper}>Torrent Hash: <span className={classes.floatRight}> {this.state.selectedTorrent["TorrentHashString"]} </span> </Paper> <Paper className={classes.paper}>Torrent Hash: <span className={classes.floatRight}> {this.state.selectedTorrent["TorrentHashString"]} </span> </Paper>
</Grid> </Grid>
@@ -72,10 +72,9 @@ class GeneralTab extends React.Component {
<Paper className={classes.paper}>Status: <span className={classes.floatRight}>{this.state.selectedTorrent["Status"]} </span> </Paper> <Paper className={classes.paper}>Status: <span className={classes.floatRight}>{this.state.selectedTorrent["Status"]} </span> </Paper>
<Paper className={classes.paper}>Percent Done: <span className={classes.floatRight}>{this.state.selectedTorrent["PercentDone"]} </span> </Paper> <Paper className={classes.paper}>Percent Done: <span className={classes.floatRight}>{this.state.selectedTorrent["PercentDone"]} </span> </Paper>
<Paper className={classes.paper}>Torrent DL Amount: <span className={classes.floatRight}>{this.state.selectedTorrent["DownloadedSize"]} </span> </Paper> <Paper className={classes.paper}>Torrent DL Amount: <span className={classes.floatRight}>{this.state.selectedTorrent["DownloadedSize"]} </span> </Paper>
<Paper className={classes.paper}>Total Upload Amount: <span className={classes.floatRight}>{this.state.selectedTorrent["Status"]} </span> </Paper> <Paper className={classes.paper}>Total Upload Amount: <span className={classes.floatRight}>{this.state.selectedTorrent["TotalUploadedSize"]} </span> </Paper>
<Paper className={classes.paper}>Seeding Ratio: <span className={classes.floatRight}>{this.state.selectedTorrent["Status"]} </span> </Paper> <Paper className={classes.paper}>Seeding Ratio: <span className={classes.floatRight}>{this.state.selectedTorrent["Ratio"]} </span> </Paper>
<Paper className={classes.paper}>ETA: <span className={classes.floatRight}>{this.state.selectedTorrent["ETA"]} </span> </Paper> <Paper className={classes.paper}>ETA: <span className={classes.floatRight}>{this.state.selectedTorrent["ETA"]} </span> </Paper>
<Paper className={classes.paper}>Status: <span className={classes.floatRight}>{this.state.selectedTorrent["Status"]} </span> </Paper>
</Grid> </Grid>
<Grid item xs={12} sm={4}> <Grid item xs={12} sm={4}>

View File

@@ -6,6 +6,7 @@ import AppBar from 'material-ui/AppBar';
import Tabs, { Tab } from 'material-ui/Tabs'; import Tabs, { Tab } from 'material-ui/Tabs';
import GeneralTab from './Tabs/generalTab'; import GeneralTab from './Tabs/generalTab';
import PeerTab from './Tabs/peerTab'; import PeerTab from './Tabs/peerTab';
import FileTab from './Tabs/fileTab';
//Redux //Redux
@@ -57,7 +58,7 @@ function TabContainer(props) {
</div> </div>
{this.props.selectedTab === 0 && <TabContainer><GeneralTab /></TabContainer>} {this.props.selectedTab === 0 && <TabContainer><GeneralTab /></TabContainer>}
{this.props.selectedTab === 1 && <TabContainer><PeerTab /></TabContainer>} {this.props.selectedTab === 1 && <TabContainer><PeerTab /></TabContainer>}
{this.props.selectedTab === 2 && <TabContainer>Files</TabContainer>} {this.props.selectedTab === 2 && <TabContainer><FileTab /></TabContainer>}
{this.props.selectedTab === 3 && <TabContainer>Speed</TabContainer>} {this.props.selectedTab === 3 && <TabContainer>Speed</TabContainer>}
{this.props.selectedTab === 4 && <TabContainer>Logger</TabContainer>} {this.props.selectedTab === 4 && <TabContainer>Logger</TabContainer>}
</div> </div>

View File

@@ -50,7 +50,7 @@ export default class addTorrentPopup extends React.Component {
//let magnetLinkSubmit = this.state.textValue; //let magnetLinkSubmit = this.state.textValue;
let magnetLinkMessage = { let magnetLinkMessage = {
messageType: "magnetLinkSubmit", messageType: "magnetLinkSubmit",
Payload: { MagnetLink: this.state.textValue} Payload: [this.state.textValue]
} }
console.log("Sending magnet link: ", magnetLinkMessage); console.log("Sending magnet link: ", magnetLinkMessage);
ws.send(JSON.stringify(magnetLinkMessage)); ws.send(JSON.stringify(magnetLinkMessage));

View File

@@ -131,12 +131,12 @@ class SimpleList extends React.Component {
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Seeding Torrents" /> <ListItemText primary="Seeding Torrents" />
</ListItem> </ListItem>
<ListItem className={this.state.activeTorrentsClass} button={true} onClick={ () => this.setFilter('Active', this.state.activeID)}> {/* <ListItem className={this.state.activeTorrentsClass} button={true} onClick={ () => this.setFilter('Active', this.state.activeID)}>
<ListItemIcon className={classes.icons}> <ListItemIcon className={classes.icons}>
<ActiveTorrentsIcon /> <ActiveTorrentsIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Active Torrents" /> <ListItemText primary="Active Torrents" />
</ListItem> </ListItem> */}
<ListItem className={this.state.completedTorrentsClass} button={true} onClick={ () => this.setFilter('Completed', this.state.completedID)}> <ListItem className={this.state.completedTorrentsClass} button={true} onClick={ () => this.setFilter('Completed', this.state.completedID)}>
<ListItemIcon className={classes.inactiveIcon}> <ListItemIcon className={classes.inactiveIcon}>
<ActiveTorrentsIcon /> <ActiveTorrentsIcon />

View File

@@ -6,3 +6,4 @@ export const SET_BUTTON_STATE = 'BUTTON_STATE';
export const SELECTION_HASHES = 'SELECTION_HASHES'; export const SELECTION_HASHES = 'SELECTION_HASHES';
export const SELECTED_TAB = 'SELECTED_TAB'; export const SELECTED_TAB = 'SELECTED_TAB';
export const PEER_LIST = 'PEER_LIST'; export const PEER_LIST = 'PEER_LIST';
export const FILE_LIST = 'FILE_LIST';

View File

@@ -3,8 +3,8 @@ import * as actionTypes from './actions';
const initialState = { const initialState = {
buttonStateDefault: [{startButton: "default", pauseButton: "default", stopButton: "default", deleteButton: "default", fSeedButton: "default", fRecheckButton: "default"}], buttonStateDefault: [{startButton: "default", stopButton: "default", deleteButton: "default", fSeedButton: "default", fRecheckButton: "default"}],
buttonState: [{startButton: "default", pauseButton: "default", stopButton: "default", deleteButton: "default", fSeedButton: "default", fRecheckButton: "default"}], buttonState: [{startButton: "default", stopButton: "default", deleteButton: "default", fSeedButton: "default", fRecheckButton: "default"}],
sorting: [], sorting: [],
selection: [], selection: [],
selectionHashes: [], selectionHashes: [],
@@ -12,6 +12,7 @@ const initialState = {
columnName: "Status", columnName: "Status",
torrentList: [], torrentList: [],
peerList: [], peerList: [],
fileList: [],
torrentDetailInfo: [], torrentDetailInfo: [],
selectedTab: 0, selectedTab: 0,
} }
@@ -57,6 +58,13 @@ const reducer = (state = initialState, action) => {
peerList: action.peerList peerList: action.peerList
} }
case actionTypes.FILE_LIST:
console.log("FILELIST REDUX......", action.fileList)
return {
...state,
fileList: action.fileList
}
case actionTypes.SET_BUTTON_STATE: case actionTypes.SET_BUTTON_STATE:
return { return {
...state, ...state,

View File

@@ -10,7 +10,7 @@ import AddTorrentFilePopup from './addTorrentFileModal';
import StartTorrentIcon from 'material-ui-icons/PlayArrow'; import StartTorrentIcon from 'material-ui-icons/PlayArrow';
import PauseTorrentIcon from 'material-ui-icons/Pause'; //import PauseTorrentIcon from 'material-ui-icons/Pause';
import StopTorrentIcon from 'material-ui-icons/Stop'; import StopTorrentIcon from 'material-ui-icons/Stop';
import DeleteTorrentIcon from 'material-ui-icons/Delete'; import DeleteTorrentIcon from 'material-ui-icons/Delete';
import RSSTorrentIcon from 'material-ui-icons/RssFeed'; import RSSTorrentIcon from 'material-ui-icons/RssFeed';
@@ -70,7 +70,7 @@ class IconButtons extends React.Component {
startTorrent = () => { startTorrent = () => {
console.log("Starting Torrents", selection) console.log("Starting Torrents", this.props.selectionHashes)
let startTorrentHashes = { let startTorrentHashes = {
MessageType: "startTorrents", MessageType: "startTorrents",
Payload: this.props.selectionHashes, Payload: this.props.selectionHashes,
@@ -79,17 +79,26 @@ class IconButtons extends React.Component {
ws.send(JSON.stringify(startTorrentHashes)) ws.send(JSON.stringify(startTorrentHashes))
} }
buttonHandler = (buttonState) => { stopTorrent = () => {
console.log("BUTTONSTATE", buttonState) let stopTorrentHashes = {
MessageType: "stopTorrents",
Payload: this.props.selectionHashes,
}
console.log("Stopping Torrents", stopTorrentHashes)
ws.send(JSON.stringify(stopTorrentHashes))
} }
componentWillReceiveProps = (nextProps) => { //if we get a new buttonstate force a button update deleteTorrent = () => {
if (this.props.buttonState != nextProps.buttonState){
this.buttonHandler(nextProps.buttonState) let deleteTorrentHashes = {
MessageType: "deleteTorrents",
Payload: this.props.selectionHashes,
} }
console.log("B1State", this.props.buttonState[0].startButton) console.log("Deleting Torrents", deleteTorrentHashes)
ws.send(JSON.stringify(deleteTorrentHashes))
} }
render() { render() {
const { classes } = this.props; const { classes } = this.props;
return ( return (
@@ -101,15 +110,15 @@ class IconButtons extends React.Component {
<ReactTooltip place="top" type="light" effect="float" /> <ReactTooltip place="top" type="light" effect="float" />
<StartTorrentIcon /> <StartTorrentIcon />
</IconButton> </IconButton>
<IconButton color={this.props.buttonState[0].pauseButton} data-tip="Pause Torrent" className={classes.button} aria-label="Pause Torrent"> {/* <IconButton color={this.props.buttonState[0].pauseButton} data-tip="Pause Torrent" className={classes.button} aria-label="Pause Torrent">
<ReactTooltip place="top" type="light" effect="float" /> <ReactTooltip place="top" type="light" effect="float" />
<PauseTorrentIcon /> <PauseTorrentIcon />
</IconButton> </IconButton> */}
<IconButton color={this.props.buttonState[0].stopButton} data-tip="Stop Torrent" className={classes.button} aria-label="Stop Torrent"> <IconButton color={this.props.buttonState[0].stopButton} data-tip="Stop Torrent" className={classes.button} onClick={this.stopTorrent} aria-label="Stop Torrent">
<ReactTooltip place="top" type="light" effect="float" /> <ReactTooltip place="top" type="light" effect="float" />
<StopTorrentIcon /> <StopTorrentIcon />
</IconButton> </IconButton>
<IconButton color={this.props.buttonState[0].deleteButton} data-tip="Delete Torrent" className={classes.button} aria-label="Delete Torrent"> <IconButton color={this.props.buttonState[0].deleteButton} data-tip="Delete Torrent" className={classes.button} onClick={this.deleteTorrent} aria-label="Delete Torrent">
<ReactTooltip place="top" type="error" effect="float" /> <ReactTooltip place="top" type="error" effect="float" />
<DeleteTorrentIcon /> <DeleteTorrentIcon />
</IconButton> </IconButton>

View File

@@ -4,7 +4,7 @@ import styles from '../node_modules/react-bootstrap-table/dist/react-bootstrap-t
import {BootstrapTable, TableHeaderColumn} from 'react-bootstrap-table'; import {BootstrapTable, TableHeaderColumn} from 'react-bootstrap-table';
import { import {
SortingState, LocalSorting, PagingState, VirtualTableLayout, SelectionState, FilteringState, LocalFiltering, SortingState, LocalSorting, PagingState, VirtualTableLayout, SelectionState, FilteringState,
} from '@devexpress/dx-react-grid'; } from '@devexpress/dx-react-grid';
import { import {
@@ -57,10 +57,9 @@ class TorrentListTable extends React.Component {
{ name: 'ETA', title: 'ETA'}, { name: 'ETA', title: 'ETA'},
{ name: 'Ratio', title: 'Ratio'}, { name: 'Ratio', title: 'Ratio'},
{ name: 'Availability', title: 'Availability'}, { name: 'Availability', title: 'Availability'},
{ name: 'TorrentHashString', title: 'Torrent Hash' }
], ],
columnOrder: ['TorrentName', 'DownloadedSize', 'Size', 'PercentDone', 'Status', 'DownloadSpeed', 'UploadSpeed','ActivePeers', 'ETA', 'Ratio', 'Availability', 'TorrentHashString'], columnOrder: ['TorrentName', 'DownloadedSize', 'Size', 'PercentDone', 'Status', 'DownloadSpeed', 'UploadSpeed','ActivePeers', 'ETA', 'Ratio', 'Availability'],
columnWidths: {TorrentName: 250, DownloadedSize: 100, Size: 100, PercentDone: 175, Status: 150, DownloadSpeed: 100, UploadSpeed: 100, ActivePeers: 100, ETA: 100, Ratio: 75, Availability: 75, TorrentHashString: 250,}, columnWidths: {TorrentName: 250, DownloadedSize: 100, Size: 100, PercentDone: 175, Status: 150, DownloadSpeed: 100, UploadSpeed: 100, ActivePeers: 100, ETA: 100, Ratio: 75, Availability: 75},
prevSelection: [], //just used to pull data from cell (temp Prevcell holder), real selection is in Redux prevSelection: [], //just used to pull data from cell (temp Prevcell holder), real selection is in Redux
}; };
@@ -90,10 +89,10 @@ class TorrentListTable extends React.Component {
determineButtonState = (selectedRows) => { //TODO run a filter to corrently determing button status... currently broken determineButtonState = (selectedRows) => { //TODO run a filter to corrently determing button status... currently broken
selectedRows.forEach(element => { selectedRows.forEach(element => {
if (element.Status === "Downloading" || "Awaiting Peers" || "Seeding") { if (element.Status === "Downloading" || "Awaiting Peers" || "Seeding") {
let buttonState = [{startButton: "default", pauseButton: "primary", stopButton: "primary", deleteButton: "accent", fSeedButton: "default", fRecheckButton: "primary"}] let buttonState = [{startButton: "default", stopButton: "primary", deleteButton: "accent", fSeedButton: "default", fRecheckButton: "primary"}]
this.props.setButtonState(buttonState) this.props.setButtonState(buttonState)
} else if (element.Status === "Completed") { } else if (element.Status === "Completed") {
let buttonState = [{startButton: "default", pauseButton: "default", stopButton: "default", deleteButton: "accent", fSeedButton: "primary", fRecheckButton: "primary"}] let buttonState = [{startButton: "default", stopButton: "default", deleteButton: "accent", fSeedButton: "primary", fRecheckButton: "primary"}]
this.props.setButtonState(buttonState) this.props.setButtonState(buttonState)
} else { } else {
this.props.setButtonState(this.props.buttonStateDefault) this.props.setButtonState(this.props.buttonStateDefault)
@@ -121,12 +120,8 @@ class TorrentListTable extends React.Component {
filterHandler = (filter) => { //TODO, figure out how to do multiple filter filterHandler = (filter) => { //TODO, figure out how to do multiple filter
console.log("Changing FIlter", filter) console.log("Changing FIlter", filter)
console.log("Filter Value", filter[0].value) if (filter.value ==="Active"){
if (filter[0].value === 'Active') { console.log("This filter doesn't fucking work")
console.log("Active Filter")
values = ['Seeding', 'Downloading'].includes
this.props.filter == [{columnName: 'Status', value: values}]
return['Downloading', 'Seeding'].includes(row[filter.columnName]);
} }
} }
@@ -137,7 +132,6 @@ class TorrentListTable extends React.Component {
<SortingState sorting={this.props.sorting} onSortingChange={this.props.changeSorting} /> <SortingState sorting={this.props.sorting} onSortingChange={this.props.changeSorting} />
<LocalSorting /> <LocalSorting />
<FilteringState filters={this.props.filter} /> <FilteringState filters={this.props.filter} />
<LocalFiltering />
<SelectionState onSelectionChange={this.changeSelection} selection={this.props.selection}/> <SelectionState onSelectionChange={this.changeSelection} selection={this.props.selection}/>
<TableView tableCellTemplate={({ row, column, style }) => { <TableView tableCellTemplate={({ row, column, style }) => {
if (column.name === 'PercentDone') { if (column.name === 'PercentDone') {