diff --git a/engine/clientStructs.go b/engine/clientStructs.go new file mode 100644 index 00000000..07cbcd52 --- /dev/null +++ b/engine/clientStructs.go @@ -0,0 +1,82 @@ +package engine + +import ( + "encoding/json" + "time" + + "github.com/anacrolix/torrent" + "github.com/anacrolix/torrent/metainfo" +) + +//All the message types are first, first the server handling messages from the client + +//Message contains the JSON messages from the client, we first unmarshal to get the messagetype, then each module unmarshalls the actual message once we know the type +type Message struct { + MessageType string + Payload json.RawMessage +} + +//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 + +//TorrentList struct contains the torrent list that is sent to the client +type TorrentList struct { //helps create the JSON structure that react expects to recieve + MessageType string `json:"MessageType"` + Totaltorrents int `json:"total"` + ClientDBstruct []ClientDB `json:"data"` +} + +//TorrentFileList supplies a list of files attached to a single torrent along with some additional information +type TorrentFileList struct { + MessageType string + TotalFiles int `json:"total"` + FileList []torrent.File `json:"fileList"` +} + +//PeerFileList returns a slice of peers +type PeerFileList struct { + MessageType string + TotalPeers int + PeerList []torrent.Peer +} + +//ClientDB struct contains the struct that is used to compose the torrentlist +type ClientDB struct { + TorrentName string `json:"TorrentName"` + DownloadedSize string `json:"DownloadedSize"` + Size string `json:"Size"` + DownloadSpeed string `json:"DownloadSpeed"` + downloadSpeedInt int64 + UploadSpeed string `json:"UploadSpeed"` + //UploadSpeedInt int64 + DataBytesWritten int64 + DataBytesRead int64 + ActivePeers string `json:"ActivePeers"` + TorrentHashString string `json:"TorrentHashString"` + PercentDone string `json:"PercentDone"` + TorrentHash metainfo.Hash + StoragePath string `json:"StorageLocation"` + DateAdded string + KnownSwarm []torrent.Peer + Status string `json:"Status"` + BytesCompleted int64 + UpdatedAt time.Time + AddedAt string + ETA string `json:"ETA"` + Label string + SourceLocation string +} diff --git a/engine/engine.go b/engine/engine.go index 02bf28ed..9db8685e 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -1,104 +1,185 @@ -package engine //main file for all the calculations and data gathering needed for creating the running torrent array +package engine //main file for all the calculations and data gathering needed for creating the running torrent arrays import ( "fmt" + "os" "time" "github.com/anacrolix/torrent" - Main "github.com/deranjer/goTorrent" + "github.com/anacrolix/torrent/metainfo" + "github.com/boltdb/bolt" + Storage "github.com/deranjer/goTorrent/storage" ) -func secondsToMinutes(inSeconds int64) string { - minutes := inSeconds / 60 - seconds := inSeconds % 60 - minutesString := fmt.Sprintf("%d", minutes) - secondsString := fmt.Sprintf("%d", seconds) - str := minutesString + " Min/ " + secondsString + " Sec" - return str +func timeOutInfo(clientTorrent *torrent.Torrent, seconds time.Duration) (deleted bool) { //forcing a timeout of the torrent if it doesn't load + timeout := make(chan bool, 1) //creating a timeout channel for our gotinfo + go func() { + time.Sleep(seconds * time.Second) + timeout <- true + }() + select { + case <-clientTorrent.GotInfo(): //attempting to retrieve info for torrent + fmt.Println("Recieved torrent info for...", clientTorrent.Name()) + clientTorrent.DownloadAll() + return false + case <-timeout: // getting info for torrent has timed out so purging the torrent + fmt.Println("Dropping Torrent") + clientTorrent.Drop() + return true + } + } -func convertSizetoGB(t float32, d float32) (tDelta string, dDelta string) { //converting sizes to MB or GB as needed and adding string - if t > 1024 && d > 1024 { - t := fmt.Sprintf("%.2f", t/1024) - t = t + " GB" - d := fmt.Sprintf("%.2f", d/1024) - 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 +//StartTorrent creates the storage.db entry and starts the 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) { + + timeOutInfo(clientTorrent, 45) //seeing if adding the torrrent times out (giving 45 seconds) + var TempHash metainfo.Hash + TempHash = clientTorrent.InfoHash() + fmt.Println(clientTorrent.Info().Source) + torrentLocalStorage.Hash = TempHash.String() // we will store the infohash to add it back later on client restart (if needed) + torrentLocalStorage.DateAdded = time.Now().Format("Jan _2 2006") + torrentLocalStorage.StoragePath = dataDir //TODO check full path information for torrent storage + torrentLocalStorage.TorrentName = clientTorrent.Name() + torrentLocalStorage.TorrentStatus = "downloading" //by default start all the torrents as downloading. + torrentLocalStorage.TorrentType = torrentFile //either "file" or "magnet" maybe more in the future + if torrentFile == "file" { + torrentLocalStorage.TorrentFileName = torrentFileName + } else { + torrentLocalStorage.TorrentFileName = "" + } + fmt.Printf("%+v\n", torrentLocalStorage) + Storage.AddTorrentLocalStorage(torrentDbStorage, torrentLocalStorage) //writing all of the data to the database + clientTorrent.DownloadAll() //starting the download +} + +//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) { + + for _, element := range TorrentLocalArray { //re-adding all the torrents we had stored from last shutdown or just added via file or magnet link + + var singleTorrent *torrent.Torrent + + if element.TorrentType == "file" { //if it is a file pull it from the uploaded torrent folder + //fmt.Println("Filename", element.TorrentFileName) + if _, err := os.Stat(element.TorrentFileName); err == nil { //if we CAN find the torrent, add it + //fmt.Println("Adding file name...", element.TorrentFileName) + singleTorrent, _ = tclient.AddTorrentFromFile(element.TorrentFileName) + } else { //if we cant find the torrent delete it + fmt.Println("File Error", err) + Storage.DelTorrentLocalStorage(db, element) + continue + } + + } else { + elementMagnet := "magnet:?xt=urn:btih:" + element.Hash //For magnet links just need to prepend the magnet part to the hash to readd + singleTorrent, _ = tclient.AddMagnet(elementMagnet) } - d := fmt.Sprintf("%.2f", d) - d = d + " MB" - t := fmt.Sprintf("%.2f", t/1024) - t = t + " GB" - return t, d - } else { - d := fmt.Sprintf("%.2f", d) - t := fmt.Sprintf("%.2f", t) - t = t + " MB" - d = d + " MB" - return t, d + + timeOut := timeOutInfo(singleTorrent, 45) + if timeOut == true { // if we did timeout then drop the torrent from the boltdb database + Storage.DelTorrentLocalStorage(db, element) //purging torrent from the local database + } + + fullClientDB := new(ClientDB) + fullStruct := singleTorrent.Stats() + + //ranging over the previous torrent array to calculate the speed for each torrent + if len(PreviousTorrentArray) > 0 { //if we actually have a previous array + for _, previousElement := range PreviousTorrentArray { + TempHash := singleTorrent.InfoHash() + if previousElement.TorrentHashString == TempHash.AsString() { //matching previous to new + CalculateTorrentSpeed(singleTorrent, fullClientDB, previousElement) + } + } + } + activePeersString := fmt.Sprintf("%v", fullStruct.ActivePeers) //converting to strings + 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 + TempHash = singleTorrent.InfoHash() + + fullClientDB.DownloadedSize = dSize + fullClientDB.Size = tSize + PercentDone := fmt.Sprintf("%.2f", bytesCompletedMB/totalSizeMB) + fullClientDB.TorrentHash = TempHash + fullClientDB.PercentDone = PercentDone + fullClientDB.DataBytesRead = fullStruct.ConnStats.DataBytesRead + fullClientDB.DataBytesWritten = fullStruct.ConnStats.DataBytesWritten + fullClientDB.ActivePeers = activePeersString + " / (" + totalPeersString + ")" + fullClientDB.TorrentHashString = TempHash.AsString() + fullClientDB.StoragePath = element.StoragePath + fullClientDB.TorrentName = element.TorrentName + fullClientDB.DateAdded = element.DateAdded + fullClientDB.BytesCompleted = singleTorrent.BytesCompleted() + CalculateTorrentETA(singleTorrent, fullClientDB) //calculating the ETA for the torrent + //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 + + RunningTorrentArray = append(RunningTorrentArray, *fullClientDB) + } + fmt.Println("RunningTorrentArrayCreated...") + return RunningTorrentArray } -func CalculateTorrentSpeed(t *torrent.Torrent, c *Main.ClientDB, oc Main.ClientDB) { - now := time.Now() - bytes := t.BytesCompleted() - bytesUpload := t.Stats().DataBytesWritten - dt := float32(now.Sub(oc.UpdatedAt)) // get the delta time length between now and last updated - db := float32(bytes - oc.BytesCompleted) //getting the delta bytes - rate := db * (float32(time.Second) / dt) // converting into seconds - 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) - if rate >= 0 { - rate = rate / 1024 / 1024 //creating integer to calculate ETA - c.DownloadSpeed = fmt.Sprintf("%.2f", rate) - c.DownloadSpeed = c.DownloadSpeed + " MB/s" - c.downloadSpeedInt = int64(rate) +//CreateFileListArray creates a file list for a single torrent that is selected and sent to the server +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 + TorrentFileListSelected := TorrentFileList{} + for _, singleTorrent := range runningTorrents { + tempHash := singleTorrent.InfoHash() + if tempHash.AsString() == selectedHash { // if our selection hash equals our torrent hash + TorrentFileListSelected.FileList = singleTorrent.Files() + TorrentFileListSelected.MessageType = "torrentFileList" + TorrentFileListSelected.TotalFiles = len(singleTorrent.Files()) + return TorrentFileListSelected + } + } - if rateUpload >= 0 { - rateUpload = rateUpload / 1024 / 1024 - c.UploadSpeed = fmt.Sprintf("%.2f", rateUpload) - c.UploadSpeed = c.UploadSpeed + " MB/s" - //c.UploadSpeedInt = int64(rateUpload) - } - //c.DownloadSpeed = fmt.Sprintf("%.2f", rate) //setting zero for download speed - //c.DownloadSpeed = c.DownloadSpeed + " MB/s" - c.UpdatedAt = now + return TorrentFileListSelected } -func calculateTorrentETA(t *torrent.Torrent, c *Main.ClientDB) { - missingBytes := t.Length() - t.BytesCompleted() - missingMB := missingBytes / 1024 / 1024 - if missingMB == 0 { - c.ETA = "Done" - } else if c.downloadSpeedInt == 0 { - c.ETA = "N/A" - } else { - ETASeconds := missingMB / c.downloadSpeedInt - str := secondsToMinutes(ETASeconds) //converting seconds to minutes + seconds - c.ETA = str +//CreatePeerListArray create a list of peers for the torrent and displays them +func CreatePeerListArray(tclient *torrent.Client, selectedHash string) PeerFileList { + runningTorrents := tclient.Torrents() + + TorrentPeerList := PeerFileList{} + for _, singleTorrent := range runningTorrents { + tempHash := singleTorrent.InfoHash() + if tempHash.AsString() == selectedHash { + TorrentPeerList.MessageType = "torrentPeerList" + TorrentPeerList.TotalPeers = len(TorrentPeerList.PeerList) + TorrentPeerList.PeerList = singleTorrent.KnownSwarm() + return TorrentPeerList + break //only looking for one result + } } + return TorrentPeerList + } -func calculateTorrentStatus(t *torrent.Torrent, c *Main.ClientDB) { - if t.Seeding() && t.Stats().ActivePeers > 0 && t.BytesMissing() == 0 { - c.Status = "Seeding" - } else if t.Stats().ActivePeers > 0 && t.BytesMissing() > 0 { - c.Status = "Downloading" - } else if t.Stats().ActivePeers == 0 && t.BytesMissing() == 0 { - c.Status = "Completed" - } else if t.Stats().ActivePeers == 0 && t.BytesMissing() > 0 { - c.Status = "Awaiting Peers" - } else { - c.Status = "Unknown" +//CreateTorrentDetailJSON creates the json response for a request for more torrent information +func CreateTorrentDetailJSON(tclient *torrent.Client, selectedHash string, torrentStorage *bolt.DB) ClientDB { + + localTorrentInfo := Storage.FetchTorrentFromStorage(torrentStorage, []byte(selectedHash)) + + runningTorrents := tclient.Torrents() + + TorrentDetailStruct := ClientDB{} + for _, singleTorrent := range runningTorrents { //ranging through the running torrents to find the one we are looking for + tempHash := singleTorrent.InfoHash() + if tempHash.AsString() == selectedHash { + fmt.Println("CreateTorrentDetail", localTorrentInfo) + return TorrentDetailStruct + break //only looking for one result + } } + return TorrentDetailStruct } diff --git a/engine/engineMaths.go b/engine/engineMaths.go new file mode 100644 index 00000000..06759c62 --- /dev/null +++ b/engine/engineMaths.go @@ -0,0 +1,105 @@ +package engine + +import ( + "fmt" + "time" + + "github.com/anacrolix/torrent" +) + +func secondsToMinutes(inSeconds int64) string { + minutes := inSeconds / 60 + seconds := inSeconds % 60 + minutesString := fmt.Sprintf("%d", minutes) + secondsString := fmt.Sprintf("%d", seconds) + str := minutesString + " Min/ " + secondsString + " Sec" + return str +} + +//ConvertSizetoGB changes the sizes +func ConvertSizetoGB(t float32, d float32) (tDelta string, dDelta string) { //converting sizes to MB or GB as needed and adding string + if t > 1024 && d > 1024 { + t := fmt.Sprintf("%.2f", t/1024) + t = t + " GB" + d := fmt.Sprintf("%.2f", d/1024) + 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) + d = d + " MB" + t := fmt.Sprintf("%.2f", t/1024) + t = t + " GB" + return t, d + } else { + d := fmt.Sprintf("%.2f", d) + t := fmt.Sprintf("%.2f", t) + t = t + " MB" + d = d + " MB" + return t, d + } +} + +//CalculateTorrentSpeed is used to calculate the torrent upload and download speed over time +func CalculateTorrentSpeed(t *torrent.Torrent, c *ClientDB, oc ClientDB) { + now := time.Now() + bytes := t.BytesCompleted() + bytesUpload := t.Stats().DataBytesWritten + dt := float32(now.Sub(oc.UpdatedAt)) // get the delta time length between now and last updated + db := float32(bytes - oc.BytesCompleted) //getting the delta bytes + rate := db * (float32(time.Second) / dt) // converting into seconds + 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) + if rate >= 0 { + rate = rate / 1024 / 1024 //creating integer to calculate ETA + c.DownloadSpeed = fmt.Sprintf("%.2f", rate) + c.DownloadSpeed = c.DownloadSpeed + " MB/s" + c.downloadSpeedInt = int64(rate) + } + if rateUpload >= 0 { + rateUpload = rateUpload / 1024 / 1024 + c.UploadSpeed = fmt.Sprintf("%.2f", rateUpload) + c.UploadSpeed = c.UploadSpeed + " MB/s" + + } + c.UpdatedAt = now +} + +//CalculateTorrentETA is used to estimate the remaining dl time of the torrent based on the speed that the MB are being downloaded +func CalculateTorrentETA(t *torrent.Torrent, c *ClientDB) { + missingBytes := t.Length() - t.BytesCompleted() + missingMB := missingBytes / 1024 / 1024 + if missingMB == 0 { + c.ETA = "Done" + } else if c.downloadSpeedInt == 0 { + c.ETA = "N/A" + } else { + ETASeconds := missingMB / c.downloadSpeedInt + str := secondsToMinutes(ETASeconds) //converting seconds to minutes + seconds + c.ETA = str + } +} + +//CalculateTorrentStatus is used to determine what the STATUS column of the frontend will display ll2 +func CalculateTorrentStatus(t *torrent.Torrent, c *ClientDB) { + if t.Seeding() && t.Stats().ActivePeers > 0 && t.BytesMissing() == 0 { + c.Status = "Seeding" + } else if t.Stats().ActivePeers > 0 && t.BytesMissing() > 0 { + c.Status = "Downloading" + } else if t.Stats().ActivePeers == 0 && t.BytesMissing() == 0 { + c.Status = "Completed" + } else if t.Stats().ActivePeers == 0 && t.BytesMissing() > 0 { + c.Status = "Awaiting Peers" + } else { + c.Status = "Unknown" + } +} diff --git a/engine/settings.go b/engine/settings.go new file mode 100644 index 00000000..6027b189 --- /dev/null +++ b/engine/settings.go @@ -0,0 +1,32 @@ +package engine //Settings.go contains all of the program settings + +import ( + "github.com/anacrolix/dht" + "github.com/anacrolix/torrent" +) + +//FullCLientSettings struct is a struct that can be read into anacrolix/torrent to setup a torrent client +type FullClientSettings struct { + Version int + torrent.Config + TFileUploadFolder string +} + +//FullClientSettingsNew creates a new torrent client config TODO read from a TOML file +func FullClientSettingsNew() FullClientSettings { + //Config := fullClientSettings //generate a new struct + + var Config FullClientSettings + + Config.Version = 1.0 + Config.DataDir = "downloads" //the full OR relative path of the default download directory for torrents + Config.TFileUploadFolder = "uploadedTorrents" + Config.Seed = true + + Config.DHTConfig = dht.ServerConfig{ + StartingNodes: dht.GlobalBootstrapAddrs, + } + + return Config + +} diff --git a/main.go b/main.go index 4cabf7e9..9ef1ef23 100644 --- a/main.go +++ b/main.go @@ -10,17 +10,13 @@ import ( "net/http" "os" "path/filepath" - "strings" - "time" "github.com/anacrolix/torrent" "github.com/gorilla/mux" "github.com/gorilla/websocket" - "github.com/anacrolix/torrent/metainfo" "github.com/boltdb/bolt" Engine "github.com/deranjer/goTorrent/engine" - Settings "github.com/deranjer/goTorrent/settings" Storage "github.com/deranjer/goTorrent/storage" ) @@ -37,160 +33,18 @@ var upgrader = websocket.Upgrader{ WriteBufferSize: 1024, } -type torrentList struct { //helps create the JSON structure that react expects to recieve - Totaltorrents int `json:"total"` - ClientDBstruct []ClientDB `json:"data"` -} - -type ClientDB struct { - TorrentName string `json:"TorrentName"` - DownloadedSize string `json:"DownloadedSize"` - Size string `json:"Size"` - DownloadSpeed string `json:"DownloadSpeed"` - downloadSpeedInt int64 - UploadSpeed string `json:"UploadSpeed"` - //UploadSpeedInt int64 - DataBytesWritten int64 - DataBytesRead int64 - ActivePeers string `json:"ActivePeers"` - TorrentHashString string `json:"TorrentHashString"` - PercentDone string `json:"PercentDone"` - TorrentHash metainfo.Hash - StoragePath string `json:"StorageLocation"` - DateAdded string - KnownSwarm []torrent.Peer - Status string `json:"Status"` - BytesCompleted int64 - UpdatedAt time.Time - ETA string `json:"ETA"` -} - func serveHome(w http.ResponseWriter, r *http.Request) { s1, _ := template.ParseFiles("templates/home.tmpl") s1.ExecuteTemplate(w, "base", map[string]string{"APP_ID": APP_ID}) } -func timeOutInfo(clientTorrent *torrent.Torrent, seconds time.Duration) (deleted bool) { //forcing a timeout of the - timeout := make(chan bool, 1) //creating a timeout channel for our gotinfo - go func() { - time.Sleep(seconds * time.Second) - timeout <- true - }() - select { - case <-clientTorrent.GotInfo(): //attempting to retrieve info for torrent - fmt.Println("Recieved torrent info..") - clientTorrent.DownloadAll() - return false - case <-timeout: // getting info for torrent has timed out so purging the torrent - fmt.Println("Dropping Torrent") - clientTorrent.Drop() - return true - } - -} - -func startTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage *Storage.TorrentLocal, torrentDbStorage *bolt.DB, dataDir string, torrentFile string, torrentFileName string) { - - timeOutInfo(clientTorrent, 45) //seeing if adding the torrrent times out (giving 45 seconds) - var TempHash metainfo.Hash - TempHash = clientTorrent.InfoHash() - fmt.Println(clientTorrent.Info().Source) - torrentLocalStorage.Hash = TempHash.String() // we will store the infohash to add it back later on client restart (if needed) - torrentLocalStorage.DateAdded = time.Now().Format("Jan _2 2006") - torrentLocalStorage.StoragePath = dataDir //TODO check full path information for torrent storage - torrentLocalStorage.TorrentName = clientTorrent.Name() - torrentLocalStorage.TorrentStatus = "downloading" //by default start all the torrents as downloading. - torrentLocalStorage.TorrentType = torrentFile //either "file" or "magnet" maybe more in the future - if torrentFile == "file" { - torrentLocalStorage.TorrentFileName = torrentFileName - } else { - torrentLocalStorage.TorrentFileName = "" - } - fmt.Printf("%+v\n", torrentLocalStorage) - Storage.AddTorrentLocalStorage(torrentDbStorage, torrentLocalStorage) //writing all of the data to the database - clientTorrent.DownloadAll() //starting the download -} - -func createRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Storage.TorrentLocal, PreviousTorrentArray []clientDB, config Settings.FullClientSettings, db *bolt.DB) (RunningTorrentArray []clientDB) { - for _, element := range TorrentLocalArray { //re-adding all the torrents we had stored from last shutdown - - var singleTorrent *torrent.Torrent - - if element.TorrentType == "file" { //if it is a file pull it from the uploaded torrent folder - //fmt.Println("Filename", element.TorrentFileName) - if _, err := os.Stat(element.TorrentFileName); err == nil { //if we CAN find the torrent, add it - //fmt.Println("Adding file name...", element.TorrentFileName) - singleTorrent, _ = tclient.AddTorrentFromFile(element.TorrentFileName) - } else { //if we cant find the torrent delete it - fmt.Println("File Error", err) - Storage.DelTorrentLocalStorage(db, element) - continue - } - - } else { - elementMagnet := "magnet:?xt=urn:btih:" + element.Hash //For magnet links just need to prepend the magnet part to the hash to readd - singleTorrent, _ = tclient.AddMagnet(elementMagnet) - } - - timeOut := timeOutInfo(singleTorrent, 45) - if timeOut == true { // if we did timeout then drop the torrent from the boltdb database - Storage.DelTorrentLocalStorage(db, element) //purging torrent from the local database - } - - fullClientDB := new(ClientDB) - fullStruct := singleTorrent.Stats() - - //ranging over the previous torrent array to calculate the speed for each torrent - if len(PreviousTorrentArray) > 0 { //if we actually have a previous array - for _, previousElement := range PreviousTorrentArray { - TempHash := singleTorrent.InfoHash() - if previousElement.TorrentHashString == TempHash.AsString() { //matching previous to new - Engine.CalculateTorrentSpeed(singleTorrent, fullClientDB, previousElement) - } - } - } - activePeersString := fmt.Sprintf("%v", fullStruct.ActivePeers) //converting to strings - 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 - TempHash = singleTorrent.InfoHash() - - fullClientDB.DownloadedSize = dSize - fullClientDB.Size = tSize - PercentDone := fmt.Sprintf("%.2f", bytesCompletedMB/totalSizeMB) - fullClientDB.TorrentHash = TempHash - fullClientDB.PercentDone = PercentDone - fullClientDB.DataBytesRead = fullStruct.ConnStats.DataBytesRead - fullClientDB.DataBytesWritten = fullStruct.ConnStats.DataBytesWritten - fullClientDB.ActivePeers = activePeersString + " / (" + totalPeersString + ")" - fullClientDB.TorrentHashString = TempHash.AsString() - fullClientDB.StoragePath = element.StoragePath - fullClientDB.TorrentName = element.TorrentName - fullClientDB.DateAdded = element.DateAdded - fullClientDB.BytesCompleted = singleTorrent.BytesCompleted() - calculateTorrentETA(singleTorrent, fullClientDB) //calculating the ETA for the torrent - //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 - - RunningTorrentArray = append(RunningTorrentArray, *fullClientDB) - - } - return RunningTorrentArray -} - -func updateClient(torrentstats []clientDB, conn *websocket.Conn) { //get the torrent client and the websocket connection to write msg +func updateClient(torrentstats []Engine.ClientDB, conn *websocket.Conn) { //get the torrent client and the websocket connection to write msg conn.WriteJSON(torrentstats) //converting to JSON and writing to the client } func main() { //setting up the torrent client - Config := Settings.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 torrentLocalStorage := new(Storage.TorrentLocal) //creating a new struct that stores all of our local storage info @@ -208,13 +62,13 @@ func main() { defer db.Close() //defering closing the database until the program closes var TorrentLocalArray = []*Storage.TorrentLocal{} //this is an array of ALL of the local storage torrents, they will be added back in via hash - var RunningTorrentArray = []clientDB{} //this stores ALL of the torrents that are running, used for client update pushes combines Local Storage and Running tclient info - var PreviousTorrentArray = []clientDB{} + var RunningTorrentArray = []Engine.ClientDB{} //this stores ALL of the torrents that are running, used for client update pushes combines Local Storage and Running tclient info + var PreviousTorrentArray = []Engine.ClientDB{} TorrentLocalArray = Storage.ReadInTorrents(db) //pulling in all the already added torrents if TorrentLocalArray != nil { //the first creation of the running torrent array - RunningTorrentArray = 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 } else { fmt.Println("Database is empty!") @@ -224,12 +78,14 @@ func main() { router.HandleFunc("/", serveHome) //Serving the main page for our SPA http.Handle("/static/", http.FileServer(http.Dir("public"))) http.Handle("/", router) - http.HandleFunc("/uploadTorrent", func(w http.ResponseWriter, r *http.Request) { //grabbing the uploaded Torrent File and adding it to the client - defer http.Redirect(w, r, "/", 301) + http.HandleFunc("/uploadTorrent", func(w http.ResponseWriter, r *http.Request) { //grabbing the uploaded Torrent File and adding it to the client TODO figure out websocket + defer http.Redirect(w, r, "/", 301) //forcing redirect to home page after file is processed file, header, err := r.FormFile("fileTest") if err != nil { fmt.Println("Error with fetching file or request issue", file) } + //torrentFileBytes, err := ioutil.ReadAll(file) TODO dump a byte slice directly into the filename + defer file.Close() //defer closing the file until we are done manipulating it var filePath = filepath.Join(Config.TFileUploadFolder, header.Filename) //creating a full filepath to store the .torrent files fileName, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666) //generating the fileName @@ -242,15 +98,16 @@ func main() { fmt.Println("Error adding Torrent from file: ", fileName.Name()) } else { fmt.Println("Adding Torrent via file", fileName) - startTorrent(clientTorrent, torrentLocalStorage, db, Config.DataDir, "file", fileName.Name()) + Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, Config.DataDir, "file", fileName.Name()) } }) http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) { //exposing the data to the TorrentLocalArray = Storage.ReadInTorrents(db) - RunningTorrentArray = createRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db) //Updates the RunningTorrentArray with the current client data as well - var torrentlistArray = new(torrentList) //the full JSON that includes the number of torrents as the root - torrentlistArray.ClientDBstruct = RunningTorrentArray + RunningTorrentArray = Engine.CreateRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db) //Updates the RunningTorrentArray with the current client data as well + var torrentlistArray = new(Engine.TorrentList) + torrentlistArray.MessageType = "torrentList" //setting the type of message + torrentlistArray.ClientDBstruct = RunningTorrentArray //the full JSON that includes the number of torrents as the root torrentlistArray.Totaltorrents = len(RunningTorrentArray) torrentlistArrayJSON, _ := json.Marshal(torrentlistArray) w.Header().Set("Content-Type", "application/json") @@ -261,60 +118,113 @@ func main() { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { - log.Println(err) + log.Println("Generic websocket error", err) return } - for { - msgType, msg, err := conn.ReadMessage() - if err != nil { - fmt.Println("Read Message Error", err) - return + runningTorrents := tclient.Torrents() //getting running torrents here since multiple cases ask for the running torrents + msg := Engine.Message{} + readJSONError := conn.ReadJSON(&msg) + if readJSONError != nil { + fmt.Println("Unable to read JSON client message", err) } - if string(msg) == "clientUpdateRequest" { //6 second update ping - fmt.Println("client Requested Update") - //time.Sleep(6 * time.Second) - err = conn.WriteMessage(msgType, []byte("clientUpdate")) - if err != nil { - fmt.Println("Websocket Write err", err) - return - } + fmt.Println("MessageType", msg.MessageType) + switch msg.MessageType { //first handling data requests + + case "torrentListRequest": + fmt.Println("client Requested TorrentList Update") TorrentLocalArray = Storage.ReadInTorrents(db) - RunningTorrentArray = 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 - var torrentlistArray = new(torrentList) + var torrentlistArray = new(Engine.TorrentList) + torrentlistArray.MessageType = "torrentList" torrentlistArray.ClientDBstruct = RunningTorrentArray torrentlistArray.Totaltorrents = len(RunningTorrentArray) //fmt.Printf("%+v\n", torrentlistArray) conn.WriteJSON(torrentlistArray) + break //updateClient(RunningTorrentArray, conn) // sending the client update information over the websocket - } else if strings.HasPrefix(string(msg), "magnet:") { - fmt.Println(string(msg)) - clientTorrent, err := tclient.AddMagnet(string(msg)) + case "torrentFileListRequest": //client requested a filelist update + fmt.Println("client Requested Filelist update") + fileListRequest := Engine.GenericPayload{} + json.Unmarshal(msg.Payload, &fileListRequest) //unmarshal into the generic payload + FileListArray := Engine.CreateFileListArray(tclient, fileListRequest.TorrentHashString) + conn.WriteJSON(FileListArray) //writing the JSON to the client + break + + case "torrentDetailedInfo": //TODO Figure out how to get single torrent info correctly + fmt.Println("client requested detailed Torrent Info") + torrentDetailRequest := Engine.GenericPayload{} + json.Unmarshal(msg.Payload, &torrentDetailRequest) + torrentDetailArray := Engine.CreateTorrentDetailJSON(tclient, torrentDetailRequest.TorrentHashString, db) + conn.WriteJSON(torrentDetailArray) + break + + 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 + json.Unmarshal(msg.Payload, &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 { fmt.Println("Magnet Error", err) } fmt.Println(clientTorrent) fmt.Printf("Adding Magnet Link") - startTorrent(clientTorrent, torrentLocalStorage, db, Config.DataDir, "magnet", "") //starting the torrent and creating local DB entry + Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, Config.DataDir, "magnet", "") //starting the torrent and creating local DB entry + break - } else if string(msg) == "torrentFileListRequest" { //client requested a filelist update - fmt.Println("client Requested Filelist update") - err = conn.WriteMessage(msgType, []byte("fileListUpdate")) - if err != nil { - fmt.Println("Websocket Write err", err) - return + case "stopTorrents": + TorrentListCommands := Engine.TorrentCommandMessage{} + json.Unmarshal(msg.Payload, &TorrentListCommands) + for _, singleTorrent := range runningTorrents { + + for _, singleSelection := range TorrentListCommands.TorrentHashStrings { + if singleTorrent.InfoHash().AsString() == singleSelection { + fmt.Println("Matched for stopping torrents") + //singleTorrent.Drop() + } + } } + break - } else { - conn.Close() - fmt.Println(string(msg)) + case "deleteTorrents": + TorrentListCommands := Engine.TorrentCommandMessage{} + json.Unmarshal(msg.Payload, &TorrentListCommands) + for _, singleTorrent := range runningTorrents { + + for _, singleSelection := range TorrentListCommands.TorrentHashStrings { + if singleTorrent.InfoHash().AsString() == singleSelection { + fmt.Println("Matched for deleting torrents") + singleTorrent.Drop() + } + } + } + break + + case "startTorrents": + fmt.Println("Starting torrents") + TorrentListCommands := Engine.TorrentCommandMessage{} + json.Unmarshal(msg.Payload, &TorrentListCommands) + for _, singleTorrent := range runningTorrents { + + for _, singleSelection := range TorrentListCommands.TorrentHashStrings { + if singleTorrent.InfoHash().AsString() == singleSelection { + fmt.Println("Matched for starting torrents") + singleTorrent.DownloadAll() + } + } + } + break + + default: + //conn.Close() + fmt.Println("Message not found, message recieved is: ", msg) return } } + }) if err := http.ListenAndServe(*httpAddr, nil); err != nil { log.Fatalf("Error listening, %v", err) diff --git a/public/static/images/draghandle.png b/public/static/images/draghandle.png deleted file mode 100644 index ceba4cbe..00000000 Binary files a/public/static/images/draghandle.png and /dev/null differ diff --git a/public/static/images/iconActiveTorrents.png b/public/static/images/iconActiveTorrents.png deleted file mode 100644 index c98be70f..00000000 Binary files a/public/static/images/iconActiveTorrents.png and /dev/null differ diff --git a/public/static/images/iconAddTorrent.png b/public/static/images/iconAddTorrent.png deleted file mode 100644 index 6e2653dc..00000000 Binary files a/public/static/images/iconAddTorrent.png and /dev/null differ diff --git a/public/static/images/iconAddTorrentLink.png b/public/static/images/iconAddTorrentLink.png deleted file mode 100644 index f7929c3c..00000000 Binary files a/public/static/images/iconAddTorrentLink.png and /dev/null differ diff --git a/public/static/images/iconDelete.png b/public/static/images/iconDelete.png deleted file mode 100644 index 666dc00f..00000000 Binary files a/public/static/images/iconDelete.png and /dev/null differ diff --git a/public/static/images/iconDownList.png b/public/static/images/iconDownList.png deleted file mode 100644 index c438dbe2..00000000 Binary files a/public/static/images/iconDownList.png and /dev/null differ diff --git a/public/static/images/iconDownload.png b/public/static/images/iconDownload.png deleted file mode 100644 index 2349d891..00000000 Binary files a/public/static/images/iconDownload.png and /dev/null differ diff --git a/public/static/images/iconInactiveTorrents.png b/public/static/images/iconInactiveTorrents.png deleted file mode 100644 index 99c8deeb..00000000 Binary files a/public/static/images/iconInactiveTorrents.png and /dev/null differ diff --git a/public/static/images/iconPause.png b/public/static/images/iconPause.png deleted file mode 100644 index d317a7fe..00000000 Binary files a/public/static/images/iconPause.png and /dev/null differ diff --git a/public/static/images/iconRSS.png b/public/static/images/iconRSS.png deleted file mode 100644 index 59f1f019..00000000 Binary files a/public/static/images/iconRSS.png and /dev/null differ diff --git a/public/static/images/iconScrollDown.png b/public/static/images/iconScrollDown.png deleted file mode 100644 index 06c0af06..00000000 Binary files a/public/static/images/iconScrollDown.png and /dev/null differ diff --git a/public/static/images/iconScrollUp.png b/public/static/images/iconScrollUp.png deleted file mode 100644 index 99fca2e1..00000000 Binary files a/public/static/images/iconScrollUp.png and /dev/null differ diff --git a/public/static/images/iconSettings.png b/public/static/images/iconSettings.png deleted file mode 100644 index 045dd943..00000000 Binary files a/public/static/images/iconSettings.png and /dev/null differ diff --git a/public/static/images/iconStart.png b/public/static/images/iconStart.png deleted file mode 100644 index e76a660b..00000000 Binary files a/public/static/images/iconStart.png and /dev/null differ diff --git a/public/static/images/iconStop.png b/public/static/images/iconStop.png deleted file mode 100644 index 13b9197b..00000000 Binary files a/public/static/images/iconStop.png and /dev/null differ diff --git a/public/static/images/iconTorrent.png b/public/static/images/iconTorrent.png deleted file mode 100644 index 96351fb1..00000000 Binary files a/public/static/images/iconTorrent.png and /dev/null differ diff --git a/public/static/images/iconUpList.png b/public/static/images/iconUpList.png deleted file mode 100644 index 7dfa68ee..00000000 Binary files a/public/static/images/iconUpList.png and /dev/null differ diff --git a/public/static/images/iconUpload.png b/public/static/images/iconUpload.png deleted file mode 100644 index e68def0b..00000000 Binary files a/public/static/images/iconUpload.png and /dev/null differ diff --git a/public/static/images/testicon.png b/public/static/images/testicon.png deleted file mode 100644 index c08f5bed..00000000 Binary files a/public/static/images/testicon.png and /dev/null differ diff --git a/public/static/js/addTorrents.js b/public/static/js/addTorrents.js deleted file mode 100644 index dc392aa5..00000000 --- a/public/static/js/addTorrents.js +++ /dev/null @@ -1,49 +0,0 @@ -// Get the modal -var modal = document.getElementById('addTorrentModal'); - -// Get the button that opens the modal -var btn = document.getElementById("addTorrentLink"); - -// Get the element that closes the modal -var span = document.getElementsByClassName("addTorrentModalClose")[0]; - - -// When the user clicks the button, open the modal -btn.onclick = function() { - modal.style.display = "block"; -} - -// When the user clicks on (x), close the modal -span.onclick = function() { - modal.style.display = "none"; -} - -// When the user clicks anywhere outside of the modal, close it -window.onclick = function(event) { - if (event.target == modal) { - modal.style.display = "none"; - } -} - -var torrentFileModal = document.getElementById('addTorrentFileModal'); - -var btnTorrentFile = document.getElementById("addTorrentFile"); - -var spanTorrentFile = document.getElementsByClassName("addTorrentFileModalClose")[0]; - - -btnTorrentFile.onclick = function() { - torrentFileModal.style.display = "block"; -} - -// When the user clicks on (x), close the modal -spanTorrentFile.onclick = function() { - torrentFileModal.style.display = "none"; -} - -// When the user clicks anywhere outside of the modal, close it -window.onclick = function(event) { - if (event.target == torrentFileModal) { - torrentFileModal.style.display = "none"; - } -} diff --git a/public/static/js/bundle.js b/public/static/js/bundle.js index 47e90128..edb1ce6b 100644 --- a/public/static/js/bundle.js +++ b/public/static/js/bundle.js @@ -73459,7 +73459,6 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // contains the font for material UI -//import PhotoCamera from 'material-ui-icons/PhotoCamera'; //Redux @@ -73504,6 +73503,16 @@ var IconButtons = function (_React$Component) { var _this = _possibleConstructorReturn(this, (IconButtons.__proto__ || Object.getPrototypeOf(IconButtons)).call(this, props)); + _this.startTorrentState = { + messageType: "startTorrents", + Payload: _this.props.selection + }; + + _this.startTorrent = function (selection) { + console.log("Starting Torrents", selection); + ws.send(); + }; + _this.buttonHandler = function (buttonState) { console.log("BUTTONSTATE", buttonState); }; @@ -73582,15 +73591,14 @@ IconButtons.propTypes = { var mapStateToProps = function mapStateToProps(state) { return { - buttonState: state.buttonState + buttonState: state.buttonState, + selection: state.selection }; }; var mapDispatchToProps = function mapDispatchToProps(dispatch) { return { - changeSelection: function changeSelection(selection) { - return dispatch({ type: actionTypes.CHANGE_SELECTION, selection: selection }); - } + //changeSelection: (selection) => dispatch({type: actionTypes.CHANGE_SELECTION, selection: selection}) }; }; @@ -81221,9 +81229,13 @@ var addTorrentPopup = function (_React$Component) { _this.setState({ open: false }); }, _this.handleSubmit = function () { _this.setState({ open: false }); - var magnetLinkSubmit = _this.state.textValue; - console.log("Sending magnet link: ", magnetLinkSubmit); - ws.send(magnetLinkSubmit); + //let magnetLinkSubmit = this.state.textValue; + var magnetLinkMessage = { + messageType: "magnetLinkSubmit", + Payload: { MagnetLink: _this.state.textValue } + }; + console.log("Sending magnet link: ", magnetLinkMessage); + ws.send(JSON.stringify(magnetLinkMessage)); }, _this.setTextValue = function (event) { _this.setState({ textValue: event.target.value }); }, _temp), _possibleConstructorReturn(_this, _ret); @@ -89953,38 +89965,45 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" var title = document.title; //Set the number of active torrents in the title var torrents = []; -//websocket is started in kickwebsocket.js and is picked up here so "ws" is already defined -ws.onmessage = function (evt) { - //When we recieve a message from the websocket - if (evt.data == "clientUpdate") { - console.log("Client Update Incoming..."); - } else { - // recieving data - console.log("Recieved Client Update..."); - var clientUpdate = JSON.parse(evt.data); - if (clientUpdate.total) { - // if it has a total field it is a torrentlist update - torrents = []; //clearing out the torrent array to make room for new (so that it does keep adding) - for (var i = 0; i < clientUpdate.total; i++) { - torrents.push({ - TorrentHashString: clientUpdate.data[i].TorrentHash, - TorrentName: clientUpdate.data[i].TorrentName, - DownloadedSize: clientUpdate.data[i].DownloadedSize, - Size: clientUpdate.data[i].Size, - DownloadSpeed: clientUpdate.data[i].DownloadSpeed, - UploadSpeed: clientUpdate.data[i].UploadSpeed, - PercentDone: clientUpdate.data[i].PercentDone, - StoragePath: clientUpdate.data[i].StoragePath, - DateAdded: clientUpdate.data[i].DateAdded, - Status: clientUpdate.data[i].Status, - BytesCompleted: clientUpdate.data[i].BytesCompleted, - ActivePeers: clientUpdate.data[i].ActivePeers, - ETA: clientUpdate.data[i].ETA - }); - } +var torrentListRequest = { + messageType: "torrentListRequest" - var newTitle = '(' + clientUpdate.total + ')' + title; //updating the title - document.title = newTitle; + //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 + var serverMessage = JSON.parse(evt.data); + if (serverMessage.MessageType == "torrentList") { + console.log("Recieved Client Update..."); + //var serverMessage = JSON.parse(evt.data); + + torrents = []; //clearing out the torrent array to make room for new (so that it does keep adding) + for (var i = 0; i < serverMessage.total; i++) { + torrents.push({ + TorrentHashString: serverMessage.data[i].TorrentHash, + TorrentName: serverMessage.data[i].TorrentName, + DownloadedSize: serverMessage.data[i].DownloadedSize, + Size: serverMessage.data[i].Size, + DownloadSpeed: serverMessage.data[i].DownloadSpeed, + UploadSpeed: serverMessage.data[i].UploadSpeed, + PercentDone: serverMessage.data[i].PercentDone, + StoragePath: serverMessage.data[i].StoragePath, + DateAdded: serverMessage.data[i].DateAdded, + Status: serverMessage.data[i].Status, + BytesCompleted: serverMessage.data[i].BytesCompleted, + ActivePeers: serverMessage.data[i].ActivePeers, + ETA: serverMessage.data[i].ETA + }); + } + var newTitle = '(' + serverMessage.total + ')' + title; //updating the title + document.title = newTitle; + } else if (serverMessage.MessageType == "fileList") { + console.log("Recieved FileListUpdate", serverMessage.fileList); + fileList = []; + for (var i = 0; i < serverMessage.total; i++) { + fileList.push({ + FileList: serverMessage.fileList[i] + + }); } } }; @@ -90029,11 +90048,8 @@ var BackendSocket = function (_React$Component) { }, { key: 'tick', value: function tick() { - ws.send("clientUpdateRequest"); //talking to the server to get the torrent list + ws.send(JSON.stringify(torrentListRequest)); //talking to the server to get the torrent list this.props.newTorrentList(torrents); - - //console.log("STATE:", this.state.torrentList) - //console.log("Torrents", torrents); } }, { key: 'render', @@ -92541,13 +92557,10 @@ var TorrentListTable = function (_React$Component) { if (selection.length === 0) { //if selection is empty buttons will be default - console.log("No Selection"); _this.props.setButtonState(_this.props.buttonStateDefault); //if no selection dispatch that to redux } else { // if we have selection continue on with logic to determine button state - var selectedRows = []; //array of all the selected Rows - selection.forEach(function (element) { selectedRows.push(_this.props.torrentList[element]); //pushing the selected rows out of torrentlist }); diff --git a/public/static/js/frontend-websocket.go b/public/static/js/frontend-websocket.go deleted file mode 100644 index e0709b78..00000000 --- a/public/static/js/frontend-websocket.go +++ /dev/null @@ -1,74 +0,0 @@ -package main - -import ( - "honnef.co/go/js/dom" - "github.com/gopherjs/websocket/websocketjs" - "github.com/gopherjs/gopherjs/js" - "github.com/johanbrandhorst/gopherjs-json" - "time" - //"honnef.co/go/js/dom" - -) - -var ( - //d = dom.GetWindow().Document() //getting the dom to manipulate it - document = dom.GetWindow().Document().(dom.HTMLDocument) - //conn = func(){websocketjs.New("ws://192.168.1.141:8000/websocket")}//creating a global JS websocket connection -) - - -func main(){ - document.AddEventListener("DOMContentLoaded", false, func(_ dom.Event){ - println("DOMLoaded...") - go ready() - }) -} - -func ready(){ - - //conn := conn() - conn, err := websocketjs.New("ws://192.168.1.141:8000/websocket") // Blocks until connection is established. - - if err != nil { - println("Error creating client websocket connection") // handle error - } - onOpen := func(ev *js.Object){ - err := conn.Send("ping!") //on startup send the ping message - if err != nil { - println("Cannot send ping message") - } - } - - onMessage := func(ev *js.Object){ - messageData := ev.Get("data").String() - if messageData == "pong"{ //if the server says a pong, send a ping back - time.Sleep(6 * time.Second) - conn.Send("ping") - } else { - clientData, err := json.Unmarshal(messageData) - if err != nil { - println("Error unmarshalling server message") - } - - println(clientData.String()) - - } - } - - onClose := func(ev *js.Object){ - println("Closing Connection....") - } - - - onError := func(ev *js.Object){ - println("Error....") - } - - conn.AddEventListener("open", false, onOpen) - conn.AddEventListener("message", false, onMessage) - conn.AddEventListener("close", false, onClose) - conn.AddEventListener("error", false, onError) - - - err = conn.Close() -} \ No newline at end of file diff --git a/public/static/js/includes.go b/public/static/js/includes.go deleted file mode 100644 index 9b85bf79..00000000 --- a/public/static/js/includes.go +++ /dev/null @@ -1,102 +0,0 @@ -d := dom.GetWindow().Document() //getting the dom to manipulate it - -logTextArea := d.GetElementByID("loggerData") - -torrentLinkSubmit := d.GetElementByID("torrentLinkSubmit") -magnetLink := d.GetElementByID("magnetLink") - -addTorrentModal := d.GetElementByID("addTorrentModal") -addTorrentLinkBtn := d.GetElementByID("addTorrentLink") // Get the button that opens the modal - -addTorrentFileModal := d.GetElementByID("addTorrentFile") -addTorrentFileModalClose := d.GetElementsByClassName("addTorrentFileModalClose") - -addTorrentModalClose := d.GetElementsByClassName("addTorrentModalClose") // Get the element that closes the modal - - - -//add magnet link modal -addTorrentLinkBtn.AddEventListener("click", false, func(event dom.Event){ - addTorrentModal.SetAttribute("display", "block") - -}) -//close torrent link modal -addTorrentModalClose[0].AddEventListener("click", false, func(event dom.Event){ - addTorrentModal.SetAttribute("display", "none") -}) -//show torrent file modal -addTorrentFileModal.AddEventListener("click", false, func(event dom.Event){ - addTorrentFileModal.SetAttribute("display", "block") -}) -//hide torrent file modal -addTorrentFileModalClose[0].AddEventListener("click", false, func(event dom.Event){ - addTorrentFileModal.SetAttribute("display", "none") -}) - -// When the user clicks anywhere outside of the modal, close it -d.AddEventListener("click", false, func(event dom.Event){ - addTorrentModal.SetAttribute("display", "none") - addTorrentLinkBtn.SetAttribute("display", "none") -}) - - - -//websocket logic -conn, err := websocketjs.New("ws://192.168.1.141:8000/websocket") // Blocks until connection is established. -if err != nil { - println("Error creating client websocket connection") // handle error -} - -onOpen := func(ev *js.Object){ - err := conn.Send("ping!") //on startup send the ping message - if err != nil { - println("Cannot send ping message") - } -} - -onMessage := func(ev *js.Object){ - messageData := ev.Get("data").String() - if messageData == "pong"{ //if the server says a pong, send a ping back - time.Sleep(6 * time.Second) - conn.Send("ping") - } else { - clientData, err := json.Unmarshal(messageData) - if err != nil { - println("Error unmarshalling server message") - } - - logTextArea.SetInnerHTML(logTextArea.InnerHTML() + "
" + "Client Update Event....") - logTextArea.SetInnerHTML(logTextArea.InnerHTML() + "
" + clientData.String()) - - } -} - -onClose := func(ev *js.Object){ - logTextArea.SetInnerHTML(logTextArea.InnerHTML() + "
" + "Connection closed") -} - - -onError := func(ev *js.Object){ - logTextArea.SetInnerHTML(logTextArea.InnerHTML() + "
" + "Error opening websocket") -} - -conn.AddEventListener("open", false, onOpen) -conn.AddEventListener("message", false, onMessage) -conn.AddEventListener("close", false, onClose) -conn.AddEventListener("error", false, onError) - - -err = conn.Close() - -torrentLinkSubmit.AddEventListener("click", false, func(event dom.Event){ //listening to the submit button for magnet link - - - - conn.Send(magnetLink.TextContent()) - logTextArea.SetInnerHTML(logTextArea.InnerHTML() + "
" + "Adding Magnet Link: " + magnetLink.TextContent()) //adding the magnet link to the log - addTorrentModal.SetAttribute("display", "none") - magnetLink.SetTextContent("") - - }) - -} \ No newline at end of file diff --git a/public/static/js/kickwebsocket.js b/public/static/js/kickwebsocket.js index 7f71bb87..68a754be 100644 --- a/public/static/js/kickwebsocket.js +++ b/public/static/js/kickwebsocket.js @@ -1,7 +1,12 @@ var ws = new WebSocket("ws://192.168.1.141:8000/websocket"); //creating websocket +var kickStart = { + messageType: "torrentListRequest" +} + ws.onopen = function() { - ws.send("clientUpdateRequest"); //sending out the first ping - console.log("Kicking off websocket to server on 192.168.1.141.....") + + ws.send(JSON.stringify(kickStart)); //sending out the first ping + console.log("Kicking off websocket to server on 192.168.1.141.....", JSON.stringify(kickStart)) }; \ No newline at end of file diff --git a/public/static/js/tabControl.js b/public/static/js/tabControl.js deleted file mode 100644 index e3d2416b..00000000 --- a/public/static/js/tabControl.js +++ /dev/null @@ -1,13 +0,0 @@ -function openTab(evt, tabName) { - var i, x, tablinks; - x = document.getElementsByClassName("tab"); - for (i = 0; i < x.length; i++) { - x[i].style.display = "none"; - } - tablinks = document.getElementsByClassName("tablink"); - for (i = 0; i < x.length; i++) { - tablinks[i].className = tablinks[i].className.replace(" activeButton", ""); - } - document.getElementById(tabName).style.display = "block"; - evt.currentTarget.className += " activeButton"; -} diff --git a/public/static/js/websocket.js b/public/static/js/websocket.js deleted file mode 100644 index a8910252..00000000 --- a/public/static/js/websocket.js +++ /dev/null @@ -1,65 +0,0 @@ -function myWebsocketStart() -{ - - var torrentLinkSubmit = document.getElementById('torrentLinkSubmit'); - var magnetLink = document.getElementById('magnetLink'); - var addTorrentModal = document.getElementById('addTorrentModal'); - var myTextArea = document.getElementById("loggerData"); - var torrentHash = document.getElementById("hash"); - - - var ws = new WebSocket("ws://192.168.1.141:8000/websocket"); //creating websocket - - ws.onopen = function() - { - // Web Socket is connected, send data using send() - ws.send("ping"); - - myTextArea.innerHTML = myTextArea.innerHTML + "
" + "First message sent"; - }; - - ws.onmessage = function (evt) - { - var myTextArea = document.getElementById("loggerData"); - if(evt.data == "pong") { - setTimeout(function(){ws.send("ping");}, 2000); - } else { - - var clientUpdate = JSON.parse(evt.data); - myTextArea.innerHTML = myTextArea.innerHTML + "
" + "Client Update Event..."; - //myTextArea.innerHTML = myTextArea.innerHTML + "
" + clientUpdate.LocalTorrentInfo.DateAdded; - myTextArea.innerHTML = myTextArea.innerHTML + "
" + evt.data; - //myTextArea.innerHTML = myTextArea.innerHTML + "
" + clientUpdate[0].TorrentHashString; - - //torrentHash.innerHTML = "Hash: " + clientUpdate[0].TorrentHashString; - - - - } - }; - - ws.onclose = function() - { - var myTextArea = document.getElementById("loggerData"); - myTextArea.innerHTML = myTextArea.innerHTML + "
" + "Connection closed"; - }; - - - torrentLinkSubmit.onclick = function(e) { - e.preventDefault(); - - var magnetLinkjs = magnetLink.value; - - ws.send(magnetLinkjs); - myTextArea.innerHTML = myTextArea.innerHTML + "
Send:" + magnetLinkjs - addTorrentModal.style.display = "none"; - magnetLink.value = ''; - } - - -} - -function sendEvent(message) -{ - ws.send(message); -} diff --git a/settings/settings.go b/settings/settings.go index 7c049f68..7a9afa21 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -1,4 +1,4 @@ -package settings +package engine import ( "github.com/anacrolix/dht" diff --git a/storage/storage.go b/storage/storage.go index 03ab57f6..87d19bca 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -16,6 +16,7 @@ type TorrentLocal struct { TorrentStatus string TorrentType string //magnet or .torrent file TorrentFileName string + Label string //for labeling torrent files } //ReadInTorrents is called to read in ALL local stored torrents in the boltdb database (called on server restart) @@ -55,7 +56,7 @@ func ReadInTorrents(torrentStorage *bolt.DB) (torrentLocalArray []*TorrentLocal) } TorrentStatus = b.Get([]byte("TorrentStatus")) if TorrentStatus == nil { - fmt.Println("Torrent Status not found in local storage") + //fmt.Println("Torrent Status not found in local storage") TorrentStatus = []byte("") } TorrentType = b.Get([]byte("TorrentType")) @@ -77,7 +78,7 @@ func ReadInTorrents(torrentStorage *bolt.DB) (torrentLocalArray []*TorrentLocal) torrentLocal.TorrentType = string(TorrentType) torrentLocal.TorrentFileName = string(TorrentFileName) - fmt.Println("Torrentlocal list: ", torrentLocal) + //fmt.Println("Torrentlocal list: ", torrentLocal) torrentLocalArray = append(torrentLocalArray, torrentLocal) //dumping it into the array return nil }) @@ -137,3 +138,63 @@ func DelTorrentLocalStorage(torrentStorage *bolt.DB, local *TorrentLocal) { }) } + +//FetchTorrentFromStorage grabs the localtorrent info from the bolt database for usage found my torrenthash +func FetchTorrentFromStorage(torrentStorage *bolt.DB, selectedHash []byte) TorrentLocal { + singleTorrentInfo := TorrentLocal{} + torrentStorage.View(func(tx *bolt.Tx) error { + b := tx.Bucket(selectedHash) + 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("") + } + + 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 +} diff --git a/torrent-project/src/BackendComm/backendWebsocket.js b/torrent-project/src/BackendComm/backendWebsocket.js index e1d505e0..1c5295be 100644 --- a/torrent-project/src/BackendComm/backendWebsocket.js +++ b/torrent-project/src/BackendComm/backendWebsocket.js @@ -14,45 +14,58 @@ var title = document.title; //Set the number of active torrents in the title let torrents= []; - +var torrentListRequest = { + messageType: "torrentListRequest" +} //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 - if(evt.data == "clientUpdate") { - console.log("Client Update Incoming...") - } else { // recieving data + var serverMessage = JSON.parse(evt.data) + if (serverMessage.MessageType == "torrentList"){ console.log("Recieved Client Update...") - var clientUpdate = JSON.parse(evt.data); - if (clientUpdate.total) { // if it has a total field it is a torrentlist update - torrents = []; //clearing out the torrent array to make room for new (so that it does keep adding) - for(var i = 0; i < clientUpdate.total; i++){ - torrents.push({ - TorrentHashString: clientUpdate.data[i].TorrentHash, - TorrentName: clientUpdate.data[i].TorrentName, - DownloadedSize: clientUpdate.data[i].DownloadedSize, - Size: clientUpdate.data[i].Size, - DownloadSpeed: clientUpdate.data[i].DownloadSpeed, - UploadSpeed: clientUpdate.data[i].UploadSpeed, - PercentDone: clientUpdate.data[i].PercentDone, - StoragePath: clientUpdate.data[i].StoragePath, - DateAdded: clientUpdate.data[i].DateAdded, - Status: clientUpdate.data[i].Status, - BytesCompleted: clientUpdate.data[i].BytesCompleted, - ActivePeers: clientUpdate.data[i].ActivePeers, - ETA: clientUpdate.data[i].ETA, - }) - } - var newTitle = '(' + clientUpdate.total + ')' + title; //updating the title - document.title = newTitle; - } else if (clientUpdate) { + //var serverMessage = JSON.parse(evt.data); + + torrents = []; //clearing out the torrent array to make room for new (so that it does keep adding) + for(var i = 0; i < serverMessage.total; i++){ + torrents.push({ + TorrentHashString: serverMessage.data[i].TorrentHash, + TorrentName: serverMessage.data[i].TorrentName, + DownloadedSize: serverMessage.data[i].DownloadedSize, + Size: serverMessage.data[i].Size, + DownloadSpeed: serverMessage.data[i].DownloadSpeed, + UploadSpeed: serverMessage.data[i].UploadSpeed, + PercentDone: serverMessage.data[i].PercentDone, + StoragePath: serverMessage.data[i].StoragePath, + DateAdded: serverMessage.data[i].DateAdded, + Status: serverMessage.data[i].Status, + BytesCompleted: serverMessage.data[i].BytesCompleted, + ActivePeers: serverMessage.data[i].ActivePeers, + ETA: serverMessage.data[i].ETA, + }) + } + var newTitle = '(' + serverMessage.total + ')' + title; //updating the title + document.title = newTitle; + } else if (serverMessage.MessageType == "fileList"){ + console.log("Recieved FileListUpdate", serverMessage.fileList) + fileList = []; + for (var i = 0; i < serverMessage.total; i++){ + fileList.push({ + FileList: serverMessage.fileList[i] + + + }) } - + + + } + } + ws.onclose = function() { console.log('Closing connection') }; @@ -76,19 +89,15 @@ class BackendSocket extends React.Component { 2000 ); - } + } componentWillUnmount() { clearInterval(this.timerID); } tick() { - ws.send("clientUpdateRequest")//talking to the server to get the torrent list - this.props.newTorrentList(torrents) - - //console.log("STATE:", this.state.torrentList) - //console.log("Torrents", torrents); - + ws.send(JSON.stringify(torrentListRequest))//talking to the server to get the torrent list + this.props.newTorrentList(torrents) } render() { diff --git a/torrent-project/src/addTorrentLinkModal.js b/torrent-project/src/addTorrentLinkModal.js index 31843e51..ac3341fe 100644 --- a/torrent-project/src/addTorrentLinkModal.js +++ b/torrent-project/src/addTorrentLinkModal.js @@ -16,6 +16,8 @@ import Icon from 'material-ui/Icon'; import IconButton from 'material-ui/IconButton'; + + const button = { fontSize: '60px', paddingRight: '20px', @@ -29,6 +31,8 @@ const inlineStyle = { export default class addTorrentPopup extends React.Component { + + state = { open: false, }; @@ -43,9 +47,13 @@ export default class addTorrentPopup extends React.Component { handleSubmit = () => { this.setState({ open: false }); - let magnetLinkSubmit = this.state.textValue; - console.log("Sending magnet link: ", magnetLinkSubmit); - ws.send(magnetLinkSubmit); + //let magnetLinkSubmit = this.state.textValue; + let magnetLinkMessage = { + messageType: "magnetLinkSubmit", + Payload: { MagnetLink: this.state.textValue} + } + console.log("Sending magnet link: ", magnetLinkMessage); + ws.send(JSON.stringify(magnetLinkMessage)); } setTextValue = (event) => { diff --git a/torrent-project/src/topMenu.js b/torrent-project/src/topMenu.js index 10684825..0b8a9876 100644 --- a/torrent-project/src/topMenu.js +++ b/torrent-project/src/topMenu.js @@ -21,7 +21,6 @@ import ReactTooltip from 'react-tooltip' import DeleteIcon from 'material-ui-icons/Delete'; import AddShoppingCartIcon from 'material-ui-icons/AddShoppingCart'; -//import PhotoCamera from 'material-ui-icons/PhotoCamera'; import BackendSocket from './BackendComm/backendWebsocket'; @@ -63,12 +62,22 @@ const styles = theme => ({ - class IconButtons extends React.Component { constructor(props){ super(props); } + + startTorrentState = { + messageType: "startTorrents", + Payload: this.props.selection, + } + + + startTorrent = (selection) => { + console.log("Starting Torrents", selection) + ws.send() + } buttonHandler = (buttonState) => { console.log("BUTTONSTATE", buttonState) @@ -128,12 +137,13 @@ IconButtons.propTypes = { const mapStateToProps = state => { return { buttonState: state.buttonState, + selection: state.selection, }; } const mapDispatchToProps = dispatch => { return { - changeSelection: (selection) => dispatch({type: actionTypes.CHANGE_SELECTION, selection: selection}) + //changeSelection: (selection) => dispatch({type: actionTypes.CHANGE_SELECTION, selection: selection}) } } diff --git a/torrent-project/src/torrentlist.js b/torrent-project/src/torrentlist.js index 1aa858e4..0a390a28 100644 --- a/torrent-project/src/torrentlist.js +++ b/torrent-project/src/torrentlist.js @@ -95,12 +95,9 @@ class TorrentListTable extends React.Component { this.props.changeSelection(selection) //dispatch selection to redux if (selection.length === 0) { //if selection is empty buttons will be default - console.log("No Selection") this.props.setButtonState(this.props.buttonStateDefault) //if no selection dispatch that to redux } else { // if we have selection continue on with logic to determine button state - const selectedRows = [] //array of all the selected Rows - selection.forEach(element => { selectedRows.push(this.props.torrentList[element]) //pushing the selected rows out of torrentlist });