6 Commits

19 changed files with 796 additions and 353 deletions

4
.gitignore vendored
View File

@@ -2,6 +2,7 @@ downloads/
downloading/ downloading/
downloaded/ downloaded/
uploadedTorrents/ uploadedTorrents/
boltBrowser/
storage.db.lock storage.db.lock
storage.db storage.db
storage.db.old storage.db.old
@@ -23,4 +24,5 @@ config.toml.old
/public/static/js/kickwebsocket.js.backup /public/static/js/kickwebsocket.js.backup
/public/static/js/kickwebsocket-generated.js /public/static/js/kickwebsocket-generated.js
clientAuth.txt clientAuth.txt
dist dist
debScripts/

3
Dockerfile Normal file
View File

@@ -0,0 +1,3 @@
FROM scratch
COPY goTorrent /
ENTRYPOINT [ "/goTorrent" ]

View File

@@ -8,13 +8,15 @@
SeedRatioStop = 1.50 #automatically stops the torrent after it reaches this seeding ratio SeedRatioStop = 1.50 #automatically stops the torrent after it reaches this seeding ratio
#Relative or absolute path accepted, the server will convert any relative path to an absolute path. #Relative or absolute path accepted, the server will convert any relative path to an absolute path.
DefaultMoveFolder = 'Z:\downloads' #default path that a finished torrent is symlinked to after completion. Torrents added via RSS will default here DefaultMoveFolder = 'downloads' #default path that a finished torrent is symlinked to after completion. Torrents added via RSS will default here
TorrentWatchFolder = 'torrentUpload' #folder path that is watched for .torrent files and adds them automatically every 5 minutes TorrentWatchFolder = 'torrentUpload' #folder path that is watched for .torrent files and adds them automatically every 5 minutes
#Limits your upload and download speed globally, all are averages and not burst protected (usually burst on start). #Limits your upload and download speed globally, all are averages and not burst protected (usually burst on start).
#Low = ~.05MB/s, Medium = ~.5MB/s, High = ~1.5MB/s #Low = ~.05MB/s, Medium = ~.5MB/s, High = ~1.5MB/s
UploadRateLimit = "Unlimited" #Options are "Low", "Medium", "High", "Unlimited" #Unlimited is default UploadRateLimit = "Unlimited" #Options are "Low", "Medium", "High", "Unlimited" #Unlimited is default
DownloadRateLimit = "Unlimited" DownloadRateLimit = "Unlimited"
#Maximum number of allowed active torrents, the rest will be queued
MaxActiveTorrents = 5
[goTorrentWebUI] [goTorrentWebUI]
#Basic goTorrentWebUI authentication (not terribly secure, implemented in JS, password is hashed to SHA256, not salted, basically don't depend on this if you require very good security) #Basic goTorrentWebUI authentication (not terribly secure, implemented in JS, password is hashed to SHA256, not salted, basically don't depend on this if you require very good security)
@@ -25,24 +27,24 @@
[notifications] [notifications]
PushBulletToken = "o.8sUHemPkTCaty3u7KnyvEBN19EkeT63g" #add your pushbullet api token here to notify of torrent completion to pushbullet PushBulletToken = "" #add your pushbullet api token here to notify of torrent completion to pushbullet
[reverseProxy] [reverseProxy]
#This is for setting up goTorrent behind a reverse Proxy (with SSL, reverse proxy with no SSL will require editing the WSS connection to a WS connection manually) #This is for setting up goTorrent behind a reverse Proxy (with SSL, reverse proxy with no SSL will require editing the WSS connection to a WS connection manually)
ProxyEnabled = true #bool, either false or true ProxyEnabled = false #bool, either false or true
#URL is CASE SENSITIVE #URL is CASE SENSITIVE
BaseURL = "derajnet.duckdns.org/gopher/" # MUST be in the format (if you have a subdomain, and must have trailing slash) "yoursubdomain.domain.org/subroute/" BaseURL = "domain.com/subroute/" # MUST be in the format (if you have a subdomain, and must have trailing slash) "yoursubdomain.domain.org/subroute/"
[EncryptionPolicy] [EncryptionPolicy]
DisableEncryption = false DisableEncryption = false
ForceEncryption = false ForceEncryption = false
PreferNoEncryption = false PreferNoEncryption = true
[torrentClientConfig] [torrentClientConfig]
DownloadDir = 'downloading' #the full OR relative path where the torrent server stores in-progress torrents DownloadDir = 'downloading' #the full OR relative path where the torrent server stores in-progress torrents
Seed = false #boolean #seed after download Seed = true #boolean #seed after download
# Never send chunks to peers. # Never send chunks to peers.
NoUpload = false #boolean NoUpload = false #boolean

View File

@@ -1,14 +1,14 @@
[serverConfig] [serverConfig]
ServerPort = ":8000" #leave format as is it expects a string with colon ServerPort = ":8000" #leave format as is it expects a string with colon
ServerAddr = "192.168.1.100" #Put in the IP address you want to bind to ServerAddr = "192.168.1.8" #Put in the IP address you want to bind to
LogLevel = "Info" # Options = Debug, Info, Warn, Error, Fatal, Panic LogLevel = "Info" # Options = Debug, Info, Warn, Error, Fatal, Panic
LogOutput = "stdout" #Options = file, stdout #file will print it to logs/server.log LogOutput = "stdout" #Options = file, stdout #file will print it to logs/server.log
SeedRatioStop = 1.50 #automatically stops the torrent after it reaches this seeding ratio SeedRatioStop = 1.50 #automatically stops the torrent after it reaches this seeding ratio
#Relative or absolute path accepted, the server will convert any relative path to an absolute path. #Relative or absolute path accepted, the server will convert any relative path to an absolute path.
DefaultMoveFolder = 'downloads' #default path that a finished torrent is symlinked to after completion. Torrents added via RSS will default here DefaultMoveFolder = 'Z:\downloads' #default path that a finished torrent is symlinked to after completion. Torrents added via RSS will default here
TorrentWatchFolder = 'torrentUpload' #folder path that is watched for .torrent files and adds them automatically every 5 minutes TorrentWatchFolder = 'torrentUpload' #folder path that is watched for .torrent files and adds them automatically every 5 minutes
#Limits your upload and download speed globally, all are averages and not burst protected (usually burst on start). #Limits your upload and download speed globally, all are averages and not burst protected (usually burst on start).
@@ -25,24 +25,24 @@
[notifications] [notifications]
PushBulletToken = "" #add your pushbullet api token here to notify of torrent completion to pushbullet PushBulletToken = "o.8sUHemPkTCaty3u7KnyvEBN19EkeT63g" #add your pushbullet api token here to notify of torrent completion to pushbullet
[reverseProxy] [reverseProxy]
#This is for setting up goTorrent behind a reverse Proxy (with SSL, reverse proxy with no SSL will require editing the WSS connection to a WS connection manually) #This is for setting up goTorrent behind a reverse Proxy (with SSL, reverse proxy with no SSL will require editing the WSS connection to a WS connection manually)
ProxyEnabled = false #bool, either false or true ProxyEnabled = false #bool, either false or true
#URL is CASE SENSITIVE #URL is CASE SENSITIVE
BaseURL = "domain.com/subroute/" # MUST be in the format (if you have a subdomain, and must have trailing slash) "yoursubdomain.domain.org/subroute/" BaseURL = "derajnet.duckdns.org/gopher/" # MUST be in the format (if you have a subdomain, and must have trailing slash) "yoursubdomain.domain.org/subroute/"
[EncryptionPolicy] [EncryptionPolicy]
DisableEncryption = false DisableEncryption = false
ForceEncryption = false ForceEncryption = false
PreferNoEncryption = true PreferNoEncryption = false
[torrentClientConfig] [torrentClientConfig]
DownloadDir = 'downloading' #the full OR relative path where the torrent server stores in-progress torrents DownloadDir = 'downloading' #the full OR relative path where the torrent server stores in-progress torrents
Seed = true #boolean #seed after download Seed = false #boolean #seed after download
# Never send chunks to peers. # Never send chunks to peers.
NoUpload = false #boolean NoUpload = false #boolean

View File

@@ -22,7 +22,7 @@ func InitializeCronEngine() *cron.Cron {
} }
//CheckTorrentWatchFolder adds torrents from a watch folder //TODO see if you can use filepath.Abs instead of changing directory //CheckTorrentWatchFolder adds torrents from a watch folder //TODO see if you can use filepath.Abs instead of changing directory
func CheckTorrentWatchFolder(c *cron.Cron, db *storm.DB, tclient *torrent.Client, torrentLocalStorage Storage.TorrentLocal, config Settings.FullClientSettings) { func CheckTorrentWatchFolder(c *cron.Cron, db *storm.DB, tclient *torrent.Client, torrentLocalStorage Storage.TorrentLocal, config Settings.FullClientSettings, torrentQueues Storage.TorrentQueues) {
c.AddFunc("@every 5m", func() { c.AddFunc("@every 5m", func() {
Logger.WithFields(logrus.Fields{"Watch Folder": config.TorrentWatchFolder}).Info("Running the watch folder cron job") Logger.WithFields(logrus.Fields{"Watch Folder": config.TorrentWatchFolder}).Info("Running the watch folder cron job")
torrentFiles, err := ioutil.ReadDir(config.TorrentWatchFolder) torrentFiles, err := ioutil.ReadDir(config.TorrentWatchFolder)
@@ -50,7 +50,7 @@ func CheckTorrentWatchFolder(c *cron.Cron, db *storm.DB, tclient *torrent.Client
os.Remove(fullFilePathAbs) //delete the torrent after adding it and copying it over os.Remove(fullFilePathAbs) //delete the torrent after adding it and copying it over
Logger.WithFields(logrus.Fields{"Source Folder": fullFilePathAbs, "Destination Folder": fullNewFilePathAbs, "Torrent": file.Name()}).Info("Added torrent from watch folder, and moved torrent file") Logger.WithFields(logrus.Fields{"Source Folder": fullFilePathAbs, "Destination Folder": fullNewFilePathAbs, "Torrent": file.Name()}).Info("Added torrent from watch folder, and moved torrent file")
StartTorrent(clientTorrent, torrentLocalStorage, db, "file", fullNewFilePathAbs, config.DefaultMoveFolder, "default", config) AddTorrent(clientTorrent, torrentLocalStorage, db, "file", fullNewFilePathAbs, config.DefaultMoveFolder, "default", config)
} }
} }
@@ -58,7 +58,7 @@ func CheckTorrentWatchFolder(c *cron.Cron, db *storm.DB, tclient *torrent.Client
} }
//RefreshRSSCron refreshes all of the RSS feeds on an hourly basis //RefreshRSSCron refreshes all of the RSS feeds on an hourly basis
func RefreshRSSCron(c *cron.Cron, db *storm.DB, tclient *torrent.Client, torrentLocalStorage Storage.TorrentLocal, config Settings.FullClientSettings) { func RefreshRSSCron(c *cron.Cron, db *storm.DB, tclient *torrent.Client, torrentLocalStorage Storage.TorrentLocal, config Settings.FullClientSettings, torrentQueues Storage.TorrentQueues) {
c.AddFunc("@hourly", func() { c.AddFunc("@hourly", func() {
torrentHashHistory := Storage.FetchHashHistory(db) torrentHashHistory := Storage.FetchHashHistory(db)
RSSFeedStore := Storage.FetchRSSFeeds(db) RSSFeedStore := Storage.FetchRSSFeeds(db)
@@ -86,7 +86,7 @@ func RefreshRSSCron(c *cron.Cron, db *storm.DB, tclient *torrent.Client, torrent
Logger.WithFields(logrus.Fields{"err": err, "Torrent": RSSTorrent.Title}).Warn("Unable to add torrent to torrent client!") Logger.WithFields(logrus.Fields{"err": err, "Torrent": RSSTorrent.Title}).Warn("Unable to add torrent to torrent client!")
break //break out of the loop entirely for this message since we hit an error break //break out of the loop entirely for this message since we hit an error
} }
StartTorrent(clientTorrent, torrentLocalStorage, db, "magnet", "", config.DefaultMoveFolder, "RSS", config) //TODO let user specify torrent default storage location and let change on fly AddTorrent(clientTorrent, torrentLocalStorage, db, "magnet", "", config.DefaultMoveFolder, "RSS", config) //TODO let user specify torrent default storage location and let change on fly
singleFeed.Torrents = append(singleFeed.Torrents, singleRSSTorrent) singleFeed.Torrents = append(singleFeed.Torrents, singleRSSTorrent)
} }

View File

@@ -68,7 +68,6 @@ func MoveAndLeaveSymlink(config Settings.FullClientSettings, tHash string, db *s
Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath, "error": err}).Error("Error Copying Folder!") Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath, "error": err}).Error("Error Copying Folder!")
return err return err
} }
//os.Chmod(newFilePath, 0777)
err = filepath.Walk(newFilePath, func(path string, info os.FileInfo, err error) error { //Walking the file path to change the permissions err = filepath.Walk(newFilePath, func(path string, info os.FileInfo, err error) error { //Walking the file path to change the permissions
if err != nil { if err != nil {
Logger.WithFields(logrus.Fields{"file": path, "error": err}).Error("Potentially non-critical error, continuing..") Logger.WithFields(logrus.Fields{"file": path, "error": err}).Error("Potentially non-critical error, continuing..")

View File

@@ -32,6 +32,10 @@ func CreateServerPushMessage(message ServerPushMessage, conn *websocket.Conn) {
conn.WriteJSON(message) conn.WriteJSON(message)
} }
func QueueJSONMessage(conn *websocket.Conn){
}
//RefreshSingleRSSFeed refreshing a single RSS feed to send to the client (so no updating database) mainly by updating the torrent list to display any changes //RefreshSingleRSSFeed refreshing a single RSS feed to send to the client (so no updating database) mainly by updating the torrent list to display any changes
func RefreshSingleRSSFeed(db *storm.DB, RSSFeed Storage.SingleRSSFeed) Storage.SingleRSSFeed { //Todo.. duplicate as cron job... any way to merge these to reduce duplication? func RefreshSingleRSSFeed(db *storm.DB, RSSFeed Storage.SingleRSSFeed) Storage.SingleRSSFeed { //Todo.. duplicate as cron job... any way to merge these to reduce duplication?
singleRSSFeed := Storage.SingleRSSFeed{URL: RSSFeed.URL, Name: RSSFeed.Name} singleRSSFeed := Storage.SingleRSSFeed{URL: RSSFeed.URL, Name: RSSFeed.Name}
@@ -129,15 +133,15 @@ func readTorrentFileFromDB(element *Storage.TorrentLocal, tclient *torrent.Clien
return singleTorrent, nil return singleTorrent, nil
} }
//StartTorrent creates the storage.db entry and starts A NEW TORRENT and adds to the running torrent array //AddTorrent 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 *storm.DB, torrentType, torrentFilePathAbs, torrentStoragePath, labelValue string, config Settings.FullClientSettings) { func AddTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage Storage.TorrentLocal, db *storm.DB, torrentType, torrentFilePathAbs, torrentStoragePath, labelValue string, config Settings.FullClientSettings) {
timedOut := timeOutInfo(clientTorrent, 45) //seeing if adding the torrent times out (giving 45 seconds) timedOut := timeOutInfo(clientTorrent, 45) //seeing if adding the torrent times out (giving 45 seconds)
if timedOut { //if we fail to add the torrent return if timedOut { //if we fail to add the torrent return
return return
} }
var TempHash metainfo.Hash var TempHash metainfo.Hash
TempHash = clientTorrent.InfoHash() TempHash = clientTorrent.InfoHash()
allStoredTorrents := Storage.FetchAllStoredTorrents(torrentDbStorage) allStoredTorrents := Storage.FetchAllStoredTorrents(db)
for _, runningTorrentHashes := range allStoredTorrents { for _, runningTorrentHashes := range allStoredTorrents {
if runningTorrentHashes.Hash == TempHash.String() { if runningTorrentHashes.Hash == TempHash.String() {
Logger.WithFields(logrus.Fields{"Hash": TempHash.String()}).Info("Torrent has duplicate hash to already running torrent... will not add to storage") Logger.WithFields(logrus.Fields{"Hash": TempHash.String()}).Info("Torrent has duplicate hash to already running torrent... will not add to storage")
@@ -164,7 +168,7 @@ func StartTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage Storage.To
} }
torrentLocalStorage.TorrentFile = torrentfile //storing the entire file in to database torrentLocalStorage.TorrentFile = torrentfile //storing the entire file in to database
} }
Logger.WithFields(logrus.Fields{"Storage Path": torrentStoragePath, "Torrent Name": clientTorrent.Name()}).Info("Adding Torrent with following storage path") Logger.WithFields(logrus.Fields{"Storage Path": torrentStoragePath, "Torrent Name": clientTorrent.Name()}).Info("Adding Torrent with following storage path, to active Queue")
torrentFiles := clientTorrent.Files() //storing all of the files in the database along with the priority torrentFiles := clientTorrent.Files() //storing all of the files in the database along with the priority
var TorrentFilePriorityArray = []Storage.TorrentFilePriority{} var TorrentFilePriorityArray = []Storage.TorrentFilePriority{}
for _, singleFile := range torrentFiles { //creating the database setup for the file array for _, singleFile := range torrentFiles { //creating the database setup for the file array
@@ -175,21 +179,16 @@ func StartTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage Storage.To
TorrentFilePriorityArray = append(TorrentFilePriorityArray, torrentFilePriority) TorrentFilePriorityArray = append(TorrentFilePriorityArray, torrentFilePriority)
} }
torrentLocalStorage.TorrentFilePriority = TorrentFilePriorityArray torrentLocalStorage.TorrentFilePriority = TorrentFilePriorityArray
Storage.AddTorrentLocalStorage(torrentDbStorage, torrentLocalStorage) //writing all of the data to the database //torrentQueues := Storage.FetchQueues(db)
clientTorrent.DownloadAll() //set all pieces to download AddTorrentToActive(&torrentLocalStorage, clientTorrent, db)
NumPieces := clientTorrent.NumPieces() //find the number of pieces Storage.AddTorrentLocalStorage(db, torrentLocalStorage) //writing all of the data to the database
clientTorrent.CancelPieces(1, NumPieces) //cancel all of the pieces to use file priority
for _, singleFile := range clientTorrent.Files() { //setting all of the file priorities to normal
singleFile.SetPriority(torrent.PiecePriorityNormal)
}
CreateServerPushMessage(ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "success", Payload: "Torrent added!"}, Conn)
} }
//CreateInitialTorrentArray adds all the torrents on program start from the database //CreateInitialTorrentArray adds all the torrents on program start from the database
func CreateInitialTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Storage.TorrentLocal, db *storm.DB) { func CreateInitialTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Storage.TorrentLocal, db *storm.DB, config Settings.FullClientSettings) {
for _, singleTorrentFromStorage := range TorrentLocalArray { for _, singleTorrentFromStorage := range TorrentLocalArray {
var singleTorrent *torrent.Torrent var singleTorrent *torrent.Torrent
var err error var err error
if singleTorrentFromStorage.TorrentType == "file" { //if it is a file pull it from the uploaded torrent folder if singleTorrentFromStorage.TorrentType == "file" { //if it is a file pull it from the uploaded torrent folder
@@ -218,22 +217,62 @@ func CreateInitialTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto
if err != nil { if err != nil {
Logger.WithFields(logrus.Fields{"torrentFile": singleTorrent.Name(), "error": err}).Error("Unable to add infobytes to the torrent!") Logger.WithFields(logrus.Fields{"torrentFile": singleTorrent.Name(), "error": err}).Error("Unable to add infobytes to the torrent!")
} }
if singleTorrentFromStorage.TorrentStatus != "Completed" && singleTorrentFromStorage.TorrentStatus != "Stopped" { torrentQueues := Storage.FetchQueues(db)
singleTorrent.DownloadAll() //set all of the pieces to download (piece prio is NE to file prio) if len(torrentQueues.ActiveTorrents) == 0 && len(torrentQueues.QueuedTorrents) == 0 { // If empty, run through all the torrents and assign them
NumPieces := singleTorrent.NumPieces() //find the number of pieces if len(torrentQueues.ActiveTorrents) < Config.MaxActiveTorrents && singleTorrentFromStorage.TorrentStatus != "Stopped" {
singleTorrent.CancelPieces(1, NumPieces) //cancel all of the pieces to use file priority if singleTorrentFromStorage.TorrentStatus == "Completed" || singleTorrentFromStorage.TorrentStatus == "Seeding" {
for _, singleFile := range singleTorrent.Files() { //setting all of the file priorities to normal Logger.WithFields(logrus.Fields{"Torrent Name": singleTorrentFromStorage.TorrentName}).Info("Completed Torrents have lower priority, adding to Queued")
singleFile.SetPriority(torrent.PiecePriorityNormal) AddTorrentToQueue(singleTorrentFromStorage, singleTorrent, db)
} else {
Logger.WithFields(logrus.Fields{"Torrent Name": singleTorrentFromStorage.TorrentName}).Info("Adding Torrent to Active Queue")
AddTorrentToActive(singleTorrentFromStorage, singleTorrent, db)
}
} else {
Logger.WithFields(logrus.Fields{"Torrent Name": singleTorrentFromStorage.TorrentName}).Info("Last resort for torrent, adding to Queued")
AddTorrentToQueue(singleTorrentFromStorage, singleTorrent, db)
}
} else { //If we already have a queue set up then assign torrents to queue
if singleTorrentFromStorage.TorrentStatus == "Queued" {
AddTorrentToQueue(singleTorrentFromStorage, singleTorrent, db)
} else {
if len(torrentQueues.ActiveTorrents) < Config.MaxActiveTorrents && singleTorrentFromStorage.TorrentStatus != "Stopped" {
AddTorrentToActive(singleTorrentFromStorage, singleTorrent, db)
} else {
AddTorrentToQueue(singleTorrentFromStorage, singleTorrent, db)
}
}
RemoveDuplicatesFromQueues(db)
}
Storage.UpdateStorageTick(db, *singleTorrentFromStorage)
}
torrentQueues := Storage.FetchQueues(db)
if len(torrentQueues.ActiveTorrents) < config.MaxActiveTorrents && len(torrentQueues.QueuedTorrents) > 0 { //after all the torrents are added, see if out active torrent list isn't full, then add from the queue
Logger.WithFields(logrus.Fields{"Max Active: ": config.MaxActiveTorrents, "Current : ": torrentQueues.ActiveTorrents}).Debug("Adding Torrents from queue to active to fill...")
maxCanSend := config.MaxActiveTorrents - len(torrentQueues.ActiveTorrents)
if maxCanSend > len(torrentQueues.QueuedTorrents) {
maxCanSend = len(torrentQueues.QueuedTorrents)
}
torrentsToStart := make([]string, maxCanSend)
copy(torrentsToStart, torrentQueues.QueuedTorrents[len(torrentsToStart)-1:])
for _, torrentStart := range torrentsToStart {
for _, singleTorrent := range tclient.Torrents() {
if singleTorrent.InfoHash().String() == torrentStart {
singleTorrentFromStorage := Storage.FetchTorrentFromStorage(db, torrentStart)
AddTorrentToActive(&singleTorrentFromStorage, singleTorrent, db)
}
} }
} }
} }
SetFilePriority(tclient, db) //Setting the desired file priority from storage SetFilePriority(tclient, db) //Setting the desired file priority from storage
Logger.WithFields(logrus.Fields{"Max Active: ": config.MaxActiveTorrents, "Current : ": torrentQueues.ActiveTorrents}).Debug("Queue after all initial torrents have been added")
} }
//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 Settings.FullClientSettings, db *storm.DB) (RunningTorrentArray []ClientDB) { func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Storage.TorrentLocal, PreviousTorrentArray []ClientDB, config Settings.FullClientSettings, db *storm.DB) (RunningTorrentArray []ClientDB) {
torrentQueues := Storage.FetchQueues(db)
Logger.WithFields(logrus.Fields{"Max Active: ": config.MaxActiveTorrents, "TorrentQueues": torrentQueues}).Debug("Current TorrentQueues")
for _, singleTorrentFromStorage := range TorrentLocalArray { for _, singleTorrentFromStorage := range TorrentLocalArray {
torrentQueues := Storage.FetchQueues(db)
var singleTorrent *torrent.Torrent var singleTorrent *torrent.Torrent
var TempHash metainfo.Hash var TempHash metainfo.Hash
for _, liveTorrent := range tclient.Torrents() { //matching the torrent from storage to the live torrent for _, liveTorrent := range tclient.Torrents() { //matching the torrent from storage to the live torrent
@@ -241,19 +280,17 @@ func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto
singleTorrent = liveTorrent singleTorrent = liveTorrent
} }
} }
tickUpdateStruct := Storage.TorrentLocal{} //we are shoving the tick updates into a torrentlocal struct to pass to storage happens at the end of the routine tickUpdateStruct := Storage.TorrentLocal{} //we are shoving the tick updates into a torrentlocal struct to pass to storage happens at the end of the routine
fullClientDB := new(ClientDB) fullClientDB := new(ClientDB)
//singleTorrentStorageInfo := Storage.FetchTorrentFromStorage(db, TempHash.String()) //pulling the single torrent info from storage () //Handling deleted torrents here
if singleTorrentFromStorage.TorrentStatus == "Dropped" { if singleTorrentFromStorage.TorrentStatus == "Dropped" {
Logger.WithFields(logrus.Fields{"selection": singleTorrentFromStorage.TorrentName}).Info("Deleting just the torrent") Logger.WithFields(logrus.Fields{"selection": singleTorrentFromStorage.TorrentName}).Info("Deleting just the torrent")
singleTorrent.Drop() singleTorrent.Drop()
Storage.DelTorrentLocalStorage(db, singleTorrentFromStorage.Hash) Storage.DelTorrentLocalStorage(db, singleTorrentFromStorage.Hash)
} }
if singleTorrentFromStorage.TorrentStatus == "DroppedData" { if singleTorrentFromStorage.TorrentStatus == "DroppedData" {
Logger.WithFields(logrus.Fields{"selection": singleTorrentFromStorage.TorrentName}).Info("Deleting just the torrent") Logger.WithFields(logrus.Fields{"selection": singleTorrentFromStorage.TorrentName}).Info("Deleting torrent and data")
singleTorrent.Drop() singleTorrent.Drop()
Storage.DelTorrentLocalStorageAndFiles(db, singleTorrentFromStorage.Hash, Config.TorrentConfig.DataDir) Storage.DelTorrentLocalStorageAndFiles(db, singleTorrentFromStorage.Hash, Config.TorrentConfig.DataDir)
@@ -281,11 +318,8 @@ func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto
Storage.UpdateStorageTick(db, tStorage) Storage.UpdateStorageTick(db, tStorage)
} }
}() }()
} }
fullStruct := singleTorrent.Stats() fullStruct := singleTorrent.Stats()
activePeersString := strconv.Itoa(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)
fullClientDB.StoragePath = singleTorrentFromStorage.StoragePath fullClientDB.StoragePath = singleTorrentFromStorage.StoragePath
@@ -319,10 +353,23 @@ func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto
} }
CalculateTorrentETA(singleTorrentFromStorage.TorrentSize, calculatedCompletedSize, fullClientDB) //needs to be here since we need the speed calculated before we can estimate the eta. CalculateTorrentETA(singleTorrentFromStorage.TorrentSize, calculatedCompletedSize, fullClientDB) //needs to be here since we need the speed calculated before we can estimate the eta.
if (len(torrentQueues.ActiveTorrents) < config.MaxActiveTorrents) && (len(torrentQueues.QueuedTorrents) > 0) { //If there is room for another torrent in active torrents, add it.
var newTorrentHash string
for _, torrentHash := range torrentQueues.QueuedTorrents {
if singleTorrentFromStorage.TorrentStatus != "Stopped" {
newTorrentHash = torrentHash
}
}
for _, torrent := range tclient.Torrents() {
if newTorrentHash == torrent.InfoHash().String() {
AddTorrentToActive(singleTorrentFromStorage, singleTorrent, db)
}
}
}
fullClientDB.TotalUploadedSize = HumanizeBytes(float32(fullClientDB.TotalUploadedBytes)) fullClientDB.TotalUploadedSize = HumanizeBytes(float32(fullClientDB.TotalUploadedBytes))
fullClientDB.UploadRatio = CalculateUploadRatio(singleTorrent, fullClientDB) //calculate the upload ratio fullClientDB.UploadRatio = CalculateUploadRatio(singleTorrent, fullClientDB) //calculate the upload ratio
CalculateTorrentStatus(singleTorrent, fullClientDB, config, singleTorrentFromStorage, calculatedCompletedSize, calculatedTotalSize) CalculateTorrentStatus(singleTorrent, fullClientDB, config, singleTorrentFromStorage, calculatedCompletedSize, calculatedTotalSize, torrentQueues, db) //add torrents to the queue, remove from queue, etc
tickUpdateStruct.UploadRatio = fullClientDB.UploadRatio tickUpdateStruct.UploadRatio = fullClientDB.UploadRatio
tickUpdateStruct.TorrentSize = calculatedTotalSize tickUpdateStruct.TorrentSize = calculatedTotalSize
@@ -333,6 +380,7 @@ func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto
RunningTorrentArray = append(RunningTorrentArray, *fullClientDB) RunningTorrentArray = append(RunningTorrentArray, *fullClientDB)
} }
ValidateQueues(db, config, tclient) //Ensure we don't have too many in activeQueue
return RunningTorrentArray return RunningTorrentArray
} }

View File

@@ -184,18 +184,177 @@ func CalculateUploadRatio(t *torrent.Torrent, c *ClientDB) string {
return uploadRatio return uploadRatio
} }
//StopTorrent stops the torrent, updates the database and sends a message. Since stoptorrent is called by each loop (individually) no need to call an array
func StopTorrent(singleTorrent *torrent.Torrent, torrentLocalStorage *Storage.TorrentLocal, db *storm.DB) {
torrentQueues := Storage.FetchQueues(db)
if torrentLocalStorage.TorrentStatus == "Stopped" { //if we are already stopped
Logger.WithFields(logrus.Fields{"Torrent Name": torrentLocalStorage.TorrentName}).Info("Torrent Already Stopped, returning...")
return
}
torrentLocalStorage.TorrentStatus = "Stopped"
torrentLocalStorage.MaxConnections = 0
singleTorrent.SetMaxEstablishedConns(0)
for _, torrentHash := range torrentQueues.ActiveTorrents { //pulling it out of activetorrents
if torrentHash == singleTorrent.InfoHash().String() {
DeleteTorrentFromQueues(singleTorrent.InfoHash().String(), db)
}
}
for _, torrentHash := range torrentQueues.QueuedTorrents { //pulling it out of queuedTorrent
if torrentHash == singleTorrent.InfoHash().String() {
DeleteTorrentFromQueues(singleTorrent.InfoHash().String(), db)
}
}
Storage.UpdateStorageTick(db, *torrentLocalStorage)
CreateServerPushMessage(ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "success", Payload: "Torrent Stopped!"}, Conn)
return
}
//AddTorrentToActive adds a torrent to the active slice
func AddTorrentToActive(torrentLocalStorage *Storage.TorrentLocal, singleTorrent *torrent.Torrent, db *storm.DB) {
torrentQueues := Storage.FetchQueues(db)
for _, torrentHash := range torrentQueues.ActiveTorrents {
if torrentHash == singleTorrent.InfoHash().String() { //If torrent already in active skip
return
}
}
for index, queuedTorrentHash := range torrentQueues.QueuedTorrents { //Removing from the queued torrents if in queued torrents
if queuedTorrentHash == singleTorrent.InfoHash().String() {
torrentQueues.QueuedTorrents = append(torrentQueues.QueuedTorrents[:index], torrentQueues.QueuedTorrents[index+1:]...)
}
}
singleTorrent.NewReader()
singleTorrent.SetMaxEstablishedConns(80)
torrentQueues.ActiveTorrents = append(torrentQueues.ActiveTorrents, singleTorrent.InfoHash().String())
torrentLocalStorage.TorrentStatus = "Running"
torrentLocalStorage.MaxConnections = 80
for _, file := range singleTorrent.Files() {
for _, sentFile := range torrentLocalStorage.TorrentFilePriority {
if file.DisplayPath() == sentFile.TorrentFilePath {
switch sentFile.TorrentFilePriority {
case "High":
file.SetPriority(torrent.PiecePriorityHigh)
case "Normal":
file.SetPriority(torrent.PiecePriorityNormal)
case "Cancel":
file.SetPriority(torrent.PiecePriorityNone)
default:
file.SetPriority(torrent.PiecePriorityNormal)
}
}
}
}
Logger.WithFields(logrus.Fields{"Torrent Name": torrentLocalStorage.TorrentName}).Info("Adding Torrent to Active Queue")
Storage.UpdateQueues(db, torrentQueues)
}
//RemoveTorrentFromActive forces a torrent to be removed from the active list if the max limit is already there and user forces a new torrent to be added
func RemoveTorrentFromActive(torrentLocalStorage *Storage.TorrentLocal, singleTorrent *torrent.Torrent, db *storm.DB) {
torrentQueues := Storage.FetchQueues(db)
for x, torrentHash := range torrentQueues.ActiveTorrents {
if torrentHash == singleTorrent.InfoHash().String() {
torrentQueues.ActiveTorrents = append(torrentQueues.ActiveTorrents[:x], torrentQueues.ActiveTorrents[x+1:]...)
torrentQueues.QueuedTorrents = append(torrentQueues.QueuedTorrents, torrentHash)
torrentLocalStorage.TorrentStatus = "Queued"
torrentLocalStorage.MaxConnections = 0
singleTorrent.SetMaxEstablishedConns(0)
Storage.UpdateQueues(db, torrentQueues)
//AddTorrentToQueue(torrentLocalStorage, singleTorrent, db) //Adding the lasttorrent from active to queued
Storage.UpdateStorageTick(db, *torrentLocalStorage)
}
}
}
//DeleteTorrentFromQueues deletes the torrent from all queues (for a stop or delete action)
func DeleteTorrentFromQueues(torrentHash string, db *storm.DB) {
torrentQueues := Storage.FetchQueues(db)
for x, torrentHashActive := range torrentQueues.ActiveTorrents {
if torrentHash == torrentHashActive {
torrentQueues.ActiveTorrents = append(torrentQueues.ActiveTorrents[:x], torrentQueues.ActiveTorrents[x+1:]...)
Storage.UpdateQueues(db, torrentQueues)
} else {
for x, torrentHashQueued := range torrentQueues.QueuedTorrents {
if torrentHash == torrentHashQueued {
torrentQueues.QueuedTorrents = append(torrentQueues.QueuedTorrents[:x], torrentQueues.QueuedTorrents[x+1:]...)
Storage.UpdateQueues(db, torrentQueues)
}
}
}
}
Logger.WithFields(logrus.Fields{"Torrent Hash": torrentHash}).Info("Removing Torrent from all Queues")
}
//AddTorrentToQueue adds a torrent to the queue
func AddTorrentToQueue(torrentLocalStorage *Storage.TorrentLocal, singleTorrent *torrent.Torrent, db *storm.DB) {
torrentQueues := Storage.FetchQueues(db)
for _, torrentHash := range torrentQueues.QueuedTorrents {
if singleTorrent.InfoHash().String() == torrentHash { //don't add duplicate to que but do everything else (TODO, maybe find a better way?)
singleTorrent.SetMaxEstablishedConns(0)
torrentLocalStorage.MaxConnections = 0
torrentLocalStorage.TorrentStatus = "Queued"
Logger.WithFields(logrus.Fields{"TorrentName": torrentLocalStorage.TorrentName}).Info("Adding torrent to the queue, not active")
Storage.UpdateStorageTick(db, *torrentLocalStorage)
return
}
}
torrentQueues.QueuedTorrents = append(torrentQueues.QueuedTorrents, singleTorrent.InfoHash().String())
singleTorrent.SetMaxEstablishedConns(0)
torrentLocalStorage.MaxConnections = 0
torrentLocalStorage.TorrentStatus = "Queued"
Logger.WithFields(logrus.Fields{"TorrentName": torrentLocalStorage.TorrentName}).Info("Adding torrent to the queue, not active")
Storage.UpdateQueues(db, torrentQueues)
Storage.UpdateStorageTick(db, *torrentLocalStorage)
}
//RemoveDuplicatesFromQueues removes any duplicates from torrentQueues.QueuedTorrents (which will happen if it is read in from DB)
func RemoveDuplicatesFromQueues(db *storm.DB) {
torrentQueues := Storage.FetchQueues(db)
for _, torrentHash := range torrentQueues.ActiveTorrents {
for i, queuedHash := range torrentQueues.QueuedTorrents {
if torrentHash == queuedHash {
torrentQueues.QueuedTorrents = append(torrentQueues.QueuedTorrents[:i], torrentQueues.QueuedTorrents[i+1:]...)
}
}
}
Storage.UpdateQueues(db, torrentQueues)
}
//ValidateQueues is a sanity check that runs every tick to make sure the queues are in order... tried to avoid this but seems to be required
func ValidateQueues(db *storm.DB, config Settings.FullClientSettings, tclient *torrent.Client) {
torrentQueues := Storage.FetchQueues(db)
for len(torrentQueues.ActiveTorrents) > config.MaxActiveTorrents {
removeTorrent := torrentQueues.ActiveTorrents[:1]
for _, singleTorrent := range tclient.Torrents() {
if singleTorrent.InfoHash().String() == removeTorrent[0] {
singleTorrentFromStorage := Storage.FetchTorrentFromStorage(db, removeTorrent[0])
RemoveTorrentFromActive(&singleTorrentFromStorage, singleTorrent, db)
}
}
}
}
//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, config Settings.FullClientSettings, tFromStorage *storage.TorrentLocal, bytesCompleted int64, totalSize int64) { func CalculateTorrentStatus(t *torrent.Torrent, c *ClientDB, config Settings.FullClientSettings, tFromStorage *storage.TorrentLocal, bytesCompleted int64, totalSize int64, torrentQueues Storage.TorrentQueues, db *storm.DB) {
if (tFromStorage.TorrentStatus == "Stopped") || (float64(c.TotalUploadedBytes)/float64(bytesCompleted) >= config.SeedRatioStop && tFromStorage.TorrentUploadLimit == true) { //If storage shows torrent stopped or if it is over the seeding ratio AND is under the global limit if tFromStorage.TorrentStatus == "Stopped" {
c.Status = "Stopped" c.Status = "Stopped"
c.MaxConnections = 0 return
t.SetMaxEstablishedConns(0) }
if float64(c.TotalUploadedBytes)/float64(bytesCompleted) >= config.SeedRatioStop && tFromStorage.TorrentUploadLimit == true { //If storage shows torrent stopped or if it is over the seeding ratio AND is under the global limit
StopTorrent(t, tFromStorage, db)
} else { //Only has 2 states in storage, stopped or running, so we know it should be running, and the websocket request handled updating the database with connections and status } else { //Only has 2 states in storage, stopped or running, so we know it should be running, and the websocket request handled updating the database with connections and status
for _, torrentHash := range torrentQueues.QueuedTorrents {
if tFromStorage.Hash == torrentHash {
c.Status = "Queued"
return
}
}
if len(torrentQueues.ActiveTorrents) < config.MaxActiveTorrents && tFromStorage.TorrentStatus == "Queued" {
AddTorrentToActive(tFromStorage, t, db)
}
bytesMissing := totalSize - bytesCompleted bytesMissing := totalSize - bytesCompleted
c.MaxConnections = 80 c.MaxConnections = 80
t.SetMaxEstablishedConns(80) t.SetMaxEstablishedConns(80)
//t.DownloadAll() //ensure that we are setting the torrent to download
if t.Seeding() && t.Stats().ActivePeers > 0 && bytesMissing == 0 { if t.Seeding() && t.Stats().ActivePeers > 0 && bytesMissing == 0 {
c.Status = "Seeding" c.Status = "Seeding"
} else if t.Stats().ActivePeers > 0 && bytesMissing > 0 { } else if t.Stats().ActivePeers > 0 && bytesMissing > 0 {

View File

@@ -21,6 +21,7 @@ let serverMessage = [];
let serverPushMessage = []; let serverPushMessage = [];
let webSocketState = false; let webSocketState = false;
let settingsFile = []; let settingsFile = [];
let tokenReturn = "";
var torrentListRequest = { var torrentListRequest = {
MessageType: "torrentListRequest" MessageType: "torrentListRequest"
@@ -29,7 +30,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
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)
@@ -134,6 +135,10 @@ ws.onmessage = function (evt) { //When we recieve a message from the websocket
settingsFile = []; settingsFile = [];
console.log("Settings File Returned", serverMessage) console.log("Settings File Returned", serverMessage)
settingsFile = serverMessage.Config settingsFile = serverMessage.Config
case "TokenReturn":
tokenReturn = serverMessage.TokenReturn
console.log("Token Returned", serverMessage)
} }
} }
@@ -222,9 +227,14 @@ class BackendSocket extends React.Component {
console.log("PROPSSERVER", this.props.serverPushMessage, "SERVERPUSH", serverPushMessage) console.log("PROPSSERVER", this.props.serverPushMessage, "SERVERPUSH", serverPushMessage)
this.props.newServerMessage(serverPushMessage) this.props.newServerMessage(serverPushMessage)
} }
if (this.props.settingsModalOpen) { //TODO don't really need to updaate every tick currently until we can edit config if (this.props.settingsModalOpen) { //TODO don't really need to update every tick currently until we can edit config
this.props.newSettingsFile(settingsFile) this.props.newSettingsFile(settingsFile)
} }
if (tokenReturn != ""){ //If we get a return token
console.log("Dispatching token return", tokenReturn)
this.props.newTokenReturn(tokenReturn)
}
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
if (ws.readyState === ws.CLOSED){ //if our websocket gets closed inform the user if (ws.readyState === ws.CLOSED){ //if our websocket gets closed inform the user
@@ -264,6 +274,9 @@ class BackendSocket extends React.Component {
if (nextProps.selectionHashes.length === 1){ //if we have a selection pass it on for the tabs to verify if (nextProps.selectionHashes.length === 1){ //if we have a selection pass it on for the tabs to verify
this.selectionHandler(nextProps.selectionHashes, nextProps.selectedTab) this.selectionHandler(nextProps.selectionHashes, nextProps.selectedTab)
} }
if (nextProps.tokenReturn != this.props.tokenReturn){ //clearing out the token if we switch from the API tab
tokenReturn = nextProps.tokenReturn
}
} }
@@ -287,6 +300,7 @@ const mapStateToProps = state => {
RSSTorrentList: state.RSSTorrentList, RSSTorrentList: state.RSSTorrentList,
serverPushMessage: state.serverPushMessage, serverPushMessage: state.serverPushMessage,
settingsModalOpen: state.settingsModalOpen, settingsModalOpen: state.settingsModalOpen,
tokenReturn: state.tokenReturn,
}; };
} }
@@ -301,9 +315,8 @@ const mapDispatchToProps = dispatch => {
RSSTorrentList: (RSSTorrentList) => dispatch({type: actionTypes.RSS_TORRENT_LIST, RSSTorrentList}), RSSTorrentList: (RSSTorrentList) => dispatch({type: actionTypes.RSS_TORRENT_LIST, RSSTorrentList}),
newServerMessage: (serverPushMessage) => dispatch({type: actionTypes.SERVER_MESSAGE, serverPushMessage}), newServerMessage: (serverPushMessage) => dispatch({type: actionTypes.SERVER_MESSAGE, serverPushMessage}),
webSocketStateUpdate: (webSocketState) => dispatch({type: actionTypes.WEBSOCKET_STATE, webSocketState}), webSocketStateUpdate: (webSocketState) => dispatch({type: actionTypes.WEBSOCKET_STATE, webSocketState}),
newSettingsFile: (settingsFile) => dispatch({type: actionTypes.NEW_SETTINGS_FILE, settingsFile}) newSettingsFile: (settingsFile) => dispatch({type: actionTypes.NEW_SETTINGS_FILE, settingsFile}),
//changeSelection: (selection) => dispatch({type: actionTypes.CHANGE_SELECTION, selection}),//forcing an update to the buttons newTokenReturn: (tokenReturn) => dispatch({type: actionTypes.TOKEN_RETURN, tokenReturn}),
} }
} }

View File

@@ -3,14 +3,18 @@ import ReactDOM from 'react-dom';
import { withStyles } from 'material-ui/styles'; import { withStyles } from 'material-ui/styles';
import Paper from 'material-ui/Paper'; import Paper from 'material-ui/Paper';
import Grid from 'material-ui/Grid'; import Grid from 'material-ui/Grid';
import Button from 'material-ui/Button';
import TextField from 'material-ui/TextField';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import * as actionTypes from '../../../../store/actions';
const styles = theme => ({ const styles = theme => ({
root: { root: {
flexGrow: 1, flexGrow: 1,
marginTop: 0, marginTop: 0,
padding: 10,
}, },
paper: { paper: {
padding: 16, padding: 16,
@@ -23,19 +27,48 @@ const styles = theme => ({
}); });
class APISettingsTab extends React.PureComponent { class APISettingsTab extends React.Component {
state = {
clientName: "",
};
requestNewKey = (keyName) => { generateKey = (event) => {
let newAuthTokenRequest = {
MessageType: "newAuthToken",
Payload: {"ClientName": this.state.clientName}
}
console.log("Sending New Auth Request: ", newAuthTokenRequest);
ws.send(JSON.stringify(newAuthTokenRequest));
this.setState({clientName: ""})
}
setClientName = (event) => {
this.setState({clientName: event.target.value})
} }
componentWillUnmount = () => {
this.props.newTokenReturn("")
}
render() { render() {
const { classes } = this.props; const { classes } = this.props;
return ( return (
<div className={classes.root}> <div className={classes.root}>
Not yet implemented! <TextField style ={{width: '50%', paddingRight: '10px'}} id="clientName" type="text" label="Client Name" placeholder="Client Name associated with the key" onChange={this.setClientName} />
<Button variant="raised" color="primary" onClick={this.generateKey}>
Generate Key
</Button>
<Paper style = {{padding: '10px'}}> <span className={classes.floatLeft}>{this.props.tokenReturn} </span></Paper>
<Grid container spacing={16}>
<Grid item xs={12} sm={4}>
</Grid>
</Grid>
</div> </div>
); );
} }
@@ -44,9 +77,15 @@ class APISettingsTab extends React.PureComponent {
const mapStateToProps = state => { const mapStateToProps = state => {
return { return {
settingsFile: state.settingsFile, tokenReturn: state.tokenReturn,
}; };
} }
export default withStyles(styles)(connect(mapStateToProps)(APISettingsTab)) const mapDispatchToProps = dispatch => {
return {
newTokenReturn: (tokenReturn) => dispatch({type: actionTypes.TOKEN_RETURN, tokenReturn}),
}
}
export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(APISettingsTab))

View File

@@ -35,6 +35,7 @@ class ClientSettingsTab extends React.PureComponent {
<Paper className={classes.paper}>HTTP Port: <span className={classes.floatRight}>{this.props.settingsFile["HTTPAddr"]} </span> </Paper> <Paper className={classes.paper}>HTTP Port: <span className={classes.floatRight}>{this.props.settingsFile["HTTPAddr"]} </span> </Paper>
<Paper className={classes.paper}>Use Proxy: <span className={classes.floatRight}>{String(this.props.settingsFile["UseProxy"])} </span> </Paper> <Paper className={classes.paper}>Use Proxy: <span className={classes.floatRight}>{String(this.props.settingsFile["UseProxy"])} </span> </Paper>
<Paper className={classes.paper}>Base URL: <span className={classes.floatRight}>{this.props.settingsFile["BaseURL"]} </span> </Paper> <Paper className={classes.paper}>Base URL: <span className={classes.floatRight}>{this.props.settingsFile["BaseURL"]} </span> </Paper>
<Paper className={classes.paper}>Max Active Torrents: <span className={classes.floatRight}>{this.props.settingsFile["MaxActiveTorrents"]} </span> </Paper>
</Grid> </Grid>

View File

@@ -53,7 +53,7 @@ class LoggingSettingsTab extends React.Component {
<Grid container spacing={8}> <Grid container spacing={8}>
<Grid item xs={12} sm={4}> <Grid item xs={12} sm={4}>
<Paper className={classes.paper}>Logging Output: <span className={classes.floatRight}>{this.props.settingsFile["LoggingOutput"]} </span></Paper> <Paper className={classes.paper}>Logging Output: <span className={classes.floatRight}>{this.props.settingsFile["LoggingOutput"]} </span></Paper>
<Paper className={classes.paper}>Logging Level: <span className={classes.floatRight}>{logLevel} </span> </Paper> <Paper className={classes.paper}>Logging Level: <span className={classes.floatRight}>{this.props.settingsFile["LoggingLevel"]} </span> </Paper>
</Grid> </Grid>

View File

@@ -14,4 +14,5 @@ export const SETTINGS_MODAL_OPEN_STATE = 'SETTINGS_MODAL_OPEN_STATE';
export const NEW_SETTINGS_FILE = 'NEW_SETTINGS_FILE'; export const NEW_SETTINGS_FILE = 'NEW_SETTINGS_FILE';
export const RSS_TORRENT_LIST = 'RSS_TORRENT_LIST'; export const RSS_TORRENT_LIST = 'RSS_TORRENT_LIST';
export const SERVER_MESSAGE = 'SERVER_MESSAGE'; export const SERVER_MESSAGE = 'SERVER_MESSAGE';
export const WEBSOCKET_STATE = 'WEBSOCKET_STATE'; export const WEBSOCKET_STATE = 'WEBSOCKET_STATE';
export const TOKEN_RETURN = 'TOKEN_RETURN';

View File

@@ -129,6 +129,13 @@ const reducer = (state = initialState, action) => {
...state, ...state,
serverPushMessage: action.serverPushMessage serverPushMessage: action.serverPushMessage
} }
case actionTypes.TOKEN_RETURN:
console.log("New token return", action.tokenReturn)
return {
... state,
tokenReturn: action.tokenReturn
}
case actionTypes.SET_BUTTON_STATE: case actionTypes.SET_BUTTON_STATE:
if (action.buttonState.length === 0) { //if selection is empty buttons will be default and selectionHashes will be blanked out and pushed to redux if (action.buttonState.length === 0) { //if selection is empty buttons will be default and selectionHashes will be blanked out and pushed to redux
@@ -144,10 +151,9 @@ const reducer = (state = initialState, action) => {
selectedRows.push(state.torrentList[element]) //pushing the selected rows out of torrentlist selectedRows.push(state.torrentList[element]) //pushing the selected rows out of torrentlist
}); });
let buttonStateTest = selectedRows.filter(element => {
let buttonStateTest = selectedRows.filter(element => { //TODO fix this bad mess... we literally just need to filter for stopped and go from there
let result = [] let result = []
if (element.Status === "Downloading" || element.Status === "Awaiting Peers" || element.Status === "Seeding" || element.Status === "Completed"){ if (element.Status === "Downloading" || element.Status === "Awaiting Peers" || element.Status === "Seeding" || element.Status === "Completed" || element.Status === "Queued"){
result.push(element.Status) result.push(element.Status)
return result return result
} }
@@ -157,7 +163,6 @@ const reducer = (state = initialState, action) => {
if (buttonStateTest.length > 0 && buttonStateTest2.length === 0){ if (buttonStateTest.length > 0 && buttonStateTest2.length === 0){
let buttonStateFinal = [{startButton: "default", stopButton: "primary", deleteButton: "secondary", fSeedButton: "default", fRecheckButton: "primary"}] let buttonStateFinal = [{startButton: "default", stopButton: "primary", deleteButton: "secondary", fSeedButton: "default", fRecheckButton: "primary"}]
console.log("ButtonStateFil")
return { return {
...state, ...state,
buttonState: buttonStateFinal buttonState: buttonStateFinal

123
main.go
View File

@@ -51,7 +51,7 @@ func serveHome(w http.ResponseWriter, r *http.Request) {
func handleAuthentication(conn *websocket.Conn, db *storm.DB) { func handleAuthentication(conn *websocket.Conn, db *storm.DB) {
msg := Engine.Message{} msg := Engine.Message{}
err := conn.ReadJSON(&msg) err := conn.ReadJSON(&msg)
conn.WriteJSON(msg) //TODO just for testing, remove //conn.WriteJSON(msg) //TODO just for testing, remove
payloadData, ok := msg.Payload.(map[string]interface{}) payloadData, ok := msg.Payload.(map[string]interface{})
clientAuthToken, tokenOk := payloadData["ClientAuthString"].(string) clientAuthToken, tokenOk := payloadData["ClientAuthString"].(string)
fmt.Println("ClientAuthToken:", clientAuthToken, "TokenOkay", tokenOk, "PayloadData", payloadData, "PayloadData Okay?", ok) fmt.Println("ClientAuthToken:", clientAuthToken, "TokenOkay", tokenOk, "PayloadData", payloadData, "PayloadData Okay?", ok)
@@ -94,6 +94,7 @@ func main() {
Engine.Logger = Logger //Injecting the logger into all the packages Engine.Logger = Logger //Injecting the logger into all the packages
Storage.Logger = Logger Storage.Logger = Logger
Settings.Logger = Logger Settings.Logger = Logger
var torrentQueues = Storage.TorrentQueues{}
Config := Settings.FullClientSettingsNew() //grabbing from settings.go Config := Settings.FullClientSettingsNew() //grabbing from settings.go
Engine.Config = Config Engine.Config = Config
if Config.LoggingOutput == "file" { if Config.LoggingOutput == "file" {
@@ -123,26 +124,33 @@ func main() {
httpAddr := Config.HTTPAddr httpAddr := Config.HTTPAddr
os.MkdirAll(Config.TFileUploadFolder, 0755) //creating a directory to store uploaded torrent files os.MkdirAll(Config.TFileUploadFolder, 0755) //creating a directory to store uploaded torrent files
os.MkdirAll(Config.TorrentWatchFolder, 0755) //creating a directory to watch for added .torrent files os.MkdirAll(Config.TorrentWatchFolder, 0755) //creating a directory to watch for added .torrent files
//Logger.WithFields(logrus.Fields{"Config": Config}).Info("Torrent Client Config has been generated...") Logger.WithFields(logrus.Fields{"Config": Config}).Info("Torrent Client Config has been generated...")
tclient, err := torrent.NewClient(&Config.TorrentConfig) //pulling out the torrent specific config to use tclient, err := torrent.NewClient(&Config.TorrentConfig) //pulling out the torrent specific config to use
if err != nil { if err != nil {
Logger.WithFields(logrus.Fields{"error": err}).Fatalf("Error creating torrent client: %s") Logger.WithFields(logrus.Fields{"error": err}).Fatalf("Error creating torrent client: %s")
} }
fmt.Printf("%+v\n", Config.TorrentConfig) //fmt.Printf("%+v\n", Config.TorrentConfig)
db, err := storm.Open("storage.db") //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 {
Logger.WithFields(logrus.Fields{"error": err}).Fatal("Error opening/creating storage.db") Logger.WithFields(logrus.Fields{"error": err}).Fatal("Error opening/creating storage.db")
} else {
Logger.WithFields(logrus.Fields{"error": err}).Info("Opening or creating storage.db...")
} }
defer db.Close() //defering closing the database until the program closes defer db.Close() //defering closing the database until the program closes
err = db.One("ID", 5, &torrentQueues)
if err != nil { //Create the torrent que database
Logger.WithFields(logrus.Fields{"error": err}).Info("No Queue database found, assuming first run, creating database")
torrentQueues.ID = 5
db.Save(&torrentQueues)
}
tokens := Storage.IssuedTokensList{} //if first run setting up the authentication tokens tokens := Storage.IssuedTokensList{} //if first run setting up the authentication tokens
var signingKey []byte var signingKey []byte
err = db.One("ID", 3, &tokens) err = db.One("ID", 3, &tokens)
if err != nil { if err != nil {
Logger.WithFields(logrus.Fields{"RSSFeedStore": tokens, "error": err}).Info("No Tokens database found, assuming first run, generating token...") Logger.WithFields(logrus.Fields{"RSSFeedStore": tokens, "error": err}).Info("No Tokens database found, assuming first run, generating token...")
fmt.Println("Error", err)
fmt.Println("MAIN TOKEN: %+v\n", tokens)
tokens.ID = 3 //creating the initial store tokens.ID = 3 //creating the initial store
claims := Settings.GoTorrentClaims{ claims := Settings.GoTorrentClaims{
"goTorrentWebUI", "goTorrentWebUI",
@@ -189,12 +197,13 @@ func main() {
TorrentLocalArray := Storage.FetchAllStoredTorrents(db) //pulling in all the already added torrents - this is an array of ALL of the local storage torrents, they will be added back in via hash TorrentLocalArray := Storage.FetchAllStoredTorrents(db) //pulling in all the already added torrents - this is an array of ALL of the local storage torrents, they will be added back in via hash
if TorrentLocalArray != nil { //the first creation of the running torrent array //since we are adding all of them in we use a coroutine... just allows the web ui to load then it will load in the torrents if TorrentLocalArray != nil { //the first creation of the running torrent array //since we are adding all of them in we use a coroutine... just allows the web ui to load then it will load in the torrents
go Engine.CreateInitialTorrentArray(tclient, TorrentLocalArray, db) //adding all of the stored torrents into the torrent client Engine.CreateInitialTorrentArray(tclient, TorrentLocalArray, db, Config) //adding all of the stored torrents into the torrent client
//TODO add GO to this
} else { } else {
Logger.Info("Database is empty, no torrents loaded") Logger.Info("Database is empty, no torrents loaded")
} }
Engine.CheckTorrentWatchFolder(cronEngine, db, tclient, torrentLocalStorage, Config) //Every 5 minutes the engine will check the specified folder for new .torrent files Engine.CheckTorrentWatchFolder(cronEngine, db, tclient, torrentLocalStorage, Config, torrentQueues) //Every 5 minutes the engine will check the specified folder for new .torrent files
Engine.RefreshRSSCron(cronEngine, db, tclient, torrentLocalStorage, Config) // Refresing the RSS feeds on an hourly basis to add torrents that show up in the RSS feed Engine.RefreshRSSCron(cronEngine, db, tclient, torrentLocalStorage, Config, torrentQueues) // Refresing the RSS feeds on an hourly basis to add torrents that show up in the RSS feed
router := mux.NewRouter() //setting up the handler for the web backend router := mux.NewRouter() //setting up the handler for the web backend
router.HandleFunc("/", serveHome) //Serving the main page for our SPA router.HandleFunc("/", serveHome) //Serving the main page for our SPA
@@ -265,7 +274,7 @@ func main() {
Logger.WithFields(logrus.Fields{"clientName": payloadData["ClientName"].(string)}).Info("New Auth Token creation request") Logger.WithFields(logrus.Fields{"clientName": payloadData["ClientName"].(string)}).Info("New Auth Token creation request")
fmt.Println("Signing Key", signingKey) fmt.Println("Signing Key", signingKey)
token := Settings.GenerateToken(claims, signingKey) token := Settings.GenerateToken(claims, signingKey)
tokenReturn := Settings.TokenReturn{TokenReturn: token} tokenReturn := Settings.TokenReturn{MessageType: "TokenReturn", TokenReturn: token}
tokensDB := Storage.FetchJWTTokens(db) tokensDB := Storage.FetchJWTTokens(db)
tokensDB.TokenNames = append(tokens.TokenNames, Storage.SingleToken{payloadData["ClientName"].(string)}) tokensDB.TokenNames = append(tokens.TokenNames, Storage.SingleToken{payloadData["ClientName"].(string)})
db.Update(&tokensDB) //adding the new token client name to the database db.Update(&tokensDB) //adding the new token client name to the database
@@ -275,7 +284,7 @@ func main() {
Logger.WithFields(logrus.Fields{"message": msg}).Debug("Client Requested TorrentList Update") Logger.WithFields(logrus.Fields{"message": msg}).Debug("Client Requested TorrentList Update")
go func() { //running updates in separate thread so can still accept commands go func() { //running updates in separate thread so can still accept commands
TorrentLocalArray = Storage.FetchAllStoredTorrents(db) //Required to re-read th database since we write to the DB and this will pull the changes from it TorrentLocalArray = Storage.FetchAllStoredTorrents(db) //Required to re-read the database since we write to the DB and this will pull the changes from it
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
torrentlistArray := Engine.TorrentList{MessageType: "torrentList", ClientDBstruct: RunningTorrentArray, Totaltorrents: len(RunningTorrentArray)} torrentlistArray := Engine.TorrentList{MessageType: "torrentList", ClientDBstruct: RunningTorrentArray, Totaltorrents: len(RunningTorrentArray)}
@@ -422,8 +431,18 @@ func main() {
} }
Logger.WithFields(logrus.Fields{"clientTorrent": clientTorrent, "magnetLink": magnetLink}).Info("Adding torrent to client!") Logger.WithFields(logrus.Fields{"clientTorrent": clientTorrent, "magnetLink": magnetLink}).Info("Adding torrent to client!")
Engine.CreateServerPushMessage(Engine.ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "info", Payload: "Received MagnetLink"}, conn) Engine.CreateServerPushMessage(Engine.ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "info", Payload: "Received MagnetLink"}, conn)
go Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, "magnet", "", storageValue, labelValue, Config) //starting the torrent and creating local DB entry if len(torrentQueues.ActiveTorrents) > Config.MaxActiveTorrents {
Logger.WithFields(logrus.Fields{"Name: ": clientTorrent.Name()}).Info("Adding New torrent to active, pushing other torrent to queue")
removeTorrent := torrentQueues.ActiveTorrents[:1]
for _, singleTorrent := range runningTorrents {
if singleTorrent.InfoHash().String() == removeTorrent[0] {
oldTorrentInfo := Storage.FetchTorrentFromStorage(db, singleTorrent.InfoHash().String())
Engine.RemoveTorrentFromActive(&oldTorrentInfo, singleTorrent, db)
Storage.UpdateStorageTick(db, oldTorrentInfo)
}
}
}
go Engine.AddTorrent(clientTorrent, torrentLocalStorage, db, "magnet", "", storageValue, labelValue, Config) //starting the torrent and creating local DB entry
} }
case "torrentFileSubmit": case "torrentFileSubmit":
@@ -469,7 +488,18 @@ func main() {
Engine.CreateServerPushMessage(Engine.ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "error", Payload: "Unable to add Torrent to torrent server"}, conn) Engine.CreateServerPushMessage(Engine.ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "error", Payload: "Unable to add Torrent to torrent server"}, conn)
} }
Logger.WithFields(logrus.Fields{"clienttorrent": clientTorrent.Name(), "filename": filePathAbs}).Info("Added torrent") Logger.WithFields(logrus.Fields{"clienttorrent": clientTorrent.Name(), "filename": filePathAbs}).Info("Added torrent")
go Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, "file", filePathAbs, storageValue, labelValue, Config) if len(torrentQueues.ActiveTorrents) >= Config.MaxActiveTorrents {
Logger.WithFields(logrus.Fields{"Name: ": clientTorrent.Name()}).Info("Adding New torrent to active, pushing other torrent to queue")
removeTorrent := torrentQueues.ActiveTorrents[:1]
for _, singleTorrent := range runningTorrents {
if singleTorrent.InfoHash().String() == removeTorrent[0] {
oldTorrentInfo := Storage.FetchTorrentFromStorage(db, singleTorrent.InfoHash().String())
Engine.RemoveTorrentFromActive(&oldTorrentInfo, singleTorrent, db)
Storage.UpdateStorageTick(db, oldTorrentInfo)
go Engine.AddTorrent(clientTorrent, torrentLocalStorage, db, "file", filePathAbs, storageValue, labelValue, Config)
}
}
}
case "stopTorrents": case "stopTorrents":
torrentHashes := payloadData["TorrentHashes"].([]interface{}) torrentHashes := payloadData["TorrentHashes"].([]interface{})
@@ -479,9 +509,16 @@ func main() {
if singleTorrent.InfoHash().String() == singleSelection { if singleTorrent.InfoHash().String() == singleSelection {
Logger.WithFields(logrus.Fields{"selection": singleSelection}).Info("Matched for stopping torrents") Logger.WithFields(logrus.Fields{"selection": singleSelection}).Info("Matched for stopping torrents")
oldTorrentInfo := Storage.FetchTorrentFromStorage(db, singleTorrent.InfoHash().String()) oldTorrentInfo := Storage.FetchTorrentFromStorage(db, singleTorrent.InfoHash().String())
oldTorrentInfo.TorrentStatus = "Stopped" Engine.StopTorrent(singleTorrent, &oldTorrentInfo, db)
oldTorrentInfo.MaxConnections = 0 if len(torrentQueues.QueuedTorrents) > 1 {
Storage.UpdateStorageTick(db, oldTorrentInfo) //Updating the torrent status addTorrent := torrentQueues.QueuedTorrents[:1]
for _, singleTorrent := range runningTorrents {
if singleTorrent.InfoHash().String() == addTorrent[0] {
Engine.AddTorrentToActive(&torrentLocalStorage, singleTorrent, db)
}
}
}
} }
} }
} }
@@ -495,6 +532,20 @@ func main() {
for _, singleSelection := range torrentHashes { for _, singleSelection := range torrentHashes {
if singleTorrent.InfoHash().String() == singleSelection { if singleTorrent.InfoHash().String() == singleSelection {
oldTorrentInfo := Storage.FetchTorrentFromStorage(db, singleTorrent.InfoHash().String()) oldTorrentInfo := Storage.FetchTorrentFromStorage(db, singleTorrent.InfoHash().String())
torrentQueues = Storage.FetchQueues(db)
for index, activeTorrentHash := range torrentQueues.ActiveTorrents { //If torrent is in the active slice, pull it
if singleTorrent.InfoHash().String() == activeTorrentHash {
singleTorrent.SetMaxEstablishedConns(0)
torrentQueues.ActiveTorrents = append(torrentQueues.ActiveTorrents[:index], torrentQueues.ActiveTorrents[index+1:]...)
}
}
for index, queuedTorrentHash := range torrentQueues.QueuedTorrents { //If torrent is in the queued slice, pull it
if singleTorrent.InfoHash().String() == queuedTorrentHash {
torrentQueues.QueuedTorrents = append(torrentQueues.QueuedTorrents[:index], torrentQueues.QueuedTorrents[index+1:]...)
}
}
Logger.WithFields(logrus.Fields{"selection": singleSelection}).Info("Matched for deleting torrents") Logger.WithFields(logrus.Fields{"selection": singleSelection}).Info("Matched for deleting torrents")
if withData { if withData {
oldTorrentInfo.TorrentStatus = "DroppedData" //Will be cleaned up the next engine loop since deleting a torrent mid loop can cause issues oldTorrentInfo.TorrentStatus = "DroppedData" //Will be cleaned up the next engine loop since deleting a torrent mid loop can cause issues
@@ -502,6 +553,7 @@ func main() {
oldTorrentInfo.TorrentStatus = "Dropped" oldTorrentInfo.TorrentStatus = "Dropped"
} }
Storage.UpdateStorageTick(db, oldTorrentInfo) Storage.UpdateStorageTick(db, oldTorrentInfo)
Storage.UpdateQueues(db, torrentQueues)
} }
} }
} }
@@ -515,34 +567,26 @@ func main() {
if singleTorrent.InfoHash().String() == singleSelection { if singleTorrent.InfoHash().String() == singleSelection {
Logger.WithFields(logrus.Fields{"infoHash": singleTorrent.InfoHash().String()}).Info("Found matching torrent to start") Logger.WithFields(logrus.Fields{"infoHash": singleTorrent.InfoHash().String()}).Info("Found matching torrent to start")
oldTorrentInfo := Storage.FetchTorrentFromStorage(db, singleTorrent.InfoHash().String()) oldTorrentInfo := Storage.FetchTorrentFromStorage(db, singleTorrent.InfoHash().String())
oldTorrentInfo.TorrentStatus = "Running" Engine.AddTorrentToActive(&oldTorrentInfo, singleTorrent, db)
oldTorrentInfo.MaxConnections = 80
singleTorrent.DownloadAll() //set all of the pieces to download (piece prio is NE to file prio)
NumPieces := singleTorrent.NumPieces() //find the number of pieces
singleTorrent.CancelPieces(1, NumPieces) //cancel all of the pieces to use file priority
for _, file := range singleTorrent.Files() {
for _, sentFile := range oldTorrentInfo.TorrentFilePriority {
if file.DisplayPath() == sentFile.TorrentFilePath {
switch sentFile.TorrentFilePriority {
case "High":
file.SetPriority(torrent.PiecePriorityHigh)
case "Normal":
file.SetPriority(torrent.PiecePriorityNormal)
case "Cancel":
file.SetPriority(torrent.PiecePriorityNone)
default:
file.SetPriority(torrent.PiecePriorityNormal)
}
}
}
}
Logger.WithFields(logrus.Fields{"Torrent": oldTorrentInfo.TorrentName}).Info("Changing database to torrent running with 80 max connections") Logger.WithFields(logrus.Fields{"Torrent": oldTorrentInfo.TorrentName}).Info("Changing database to torrent running with 80 max connections")
Storage.UpdateStorageTick(db, oldTorrentInfo) //Updating the torrent status Storage.UpdateStorageTick(db, oldTorrentInfo) //Updating the torrent status
} }
torrentQueues = Storage.FetchQueues(db)
if len(torrentQueues.ActiveTorrents) > Config.MaxActiveTorrents { //Since we are starting a new torrent stop the first torrent in the que if running is full
//removeTorrent := torrentQueues.ActiveTorrents[len(torrentQueues.ActiveTorrents)-1]
removeTorrent := torrentQueues.ActiveTorrents[:1]
for _, singleTorrent := range runningTorrents {
if singleTorrent.InfoHash().String() == removeTorrent[0] {
oldTorrentInfo := Storage.FetchTorrentFromStorage(db, singleTorrent.InfoHash().String())
Engine.RemoveTorrentFromActive(&oldTorrentInfo, singleTorrent, db)
Storage.UpdateStorageTick(db, oldTorrentInfo)
}
}
}
} }
} }
case "forceUploadTorrents": case "forceUploadTorrents": //TODO allow force to override total limit of queued torrents?
torrentHashes := payloadData["TorrentHashes"].([]interface{}) torrentHashes := payloadData["TorrentHashes"].([]interface{})
Logger.WithFields(logrus.Fields{"selection": msg.Payload}).Info("Matched for force Uploading Torrents") Logger.WithFields(logrus.Fields{"selection": msg.Payload}).Info("Matched for force Uploading Torrents")
Engine.CreateServerPushMessage(Engine.ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "info", Payload: "Received Force Start Request"}, conn) Engine.CreateServerPushMessage(Engine.ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "info", Payload: "Received Force Start Request"}, conn)
@@ -554,7 +598,6 @@ func main() {
oldTorrentInfo.TorrentUploadLimit = false // no upload limit for this torrent oldTorrentInfo.TorrentUploadLimit = false // no upload limit for this torrent
oldTorrentInfo.TorrentStatus = "Running" oldTorrentInfo.TorrentStatus = "Running"
oldTorrentInfo.MaxConnections = 80 oldTorrentInfo.MaxConnections = 80
fmt.Println("OldtorrentinfoName", oldTorrentInfo.TorrentName)
Logger.WithFields(logrus.Fields{"NewMax": oldTorrentInfo.MaxConnections, "Torrent": oldTorrentInfo.TorrentName}).Info("Setting max connection from zero to 80") Logger.WithFields(logrus.Fields{"NewMax": oldTorrentInfo.MaxConnections, "Torrent": oldTorrentInfo.TorrentName}).Info("Setting max connection from zero to 80")
Storage.UpdateStorageTick(db, oldTorrentInfo) //Updating the torrent status Storage.UpdateStorageTick(db, oldTorrentInfo) //Updating the torrent status
} }
@@ -619,7 +662,7 @@ func main() {
} else { } else {
err := http.ListenAndServe(httpAddr, nil) //Can't send proxy headers if not used since that can be a security issue err := http.ListenAndServe(httpAddr, nil) //Can't send proxy headers if not used since that can be a security issue
if err != nil { if err != nil {
Logger.WithFields(logrus.Fields{"error": err}).Fatal("Unable to listen on the http Server with no proxy headers!") Logger.WithFields(logrus.Fields{"error": err}).Fatal("Unable to listen on the http Server! (Maybe wrong IP in config, port already in use?) (Config: Not using proxy, see error for more details)")
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -8,12 +8,15 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
//AuthRequest is a struct sent by a client with an authstring (JWT Token) to validate they have access to the server
type AuthRequest struct { type AuthRequest struct {
MessageType string `json:"MessageType"` MessageType string `json:"MessageType"`
AuthString string `json:"AuthString"` AuthString string `json:"AuthString"`
} }
//TokenReturn is a struct sent by the server to a client with a new generated authstring
type TokenReturn struct { type TokenReturn struct {
MessageType string `json:"MessageType"`
TokenReturn string `json:"TokenReturn"` TokenReturn string `json:"TokenReturn"`
} }

View File

@@ -40,6 +40,7 @@ type FullClientSettings struct {
DefaultMoveFolder string DefaultMoveFolder string
TorrentWatchFolder string TorrentWatchFolder string
ClientConnectSettings ClientConnectSettings
MaxActiveTorrents int
} }
//default is called if there is a parsing error //default is called if there is a parsing error
@@ -70,6 +71,8 @@ func dhtServerSettings(dhtConfig dht.ServerConfig) dht.ServerConfig {
func calculateRateLimiters(uploadRate, downloadRate string) (*rate.Limiter, *rate.Limiter) { //TODO reorg func calculateRateLimiters(uploadRate, downloadRate string) (*rate.Limiter, *rate.Limiter) { //TODO reorg
var uploadRateLimiterSize int var uploadRateLimiterSize int
var downloadRateLimiterSize int var downloadRateLimiterSize int
var downloadRateLimiter *rate.Limiter
var uploadRateLimiter *rate.Limiter
switch uploadRate { switch uploadRate {
case "Low": case "Low":
@@ -79,8 +82,8 @@ func calculateRateLimiters(uploadRate, downloadRate string) (*rate.Limiter, *rat
case "High": case "High":
uploadRateLimiterSize = 1500000 uploadRateLimiterSize = 1500000
default: default:
downloadRateLimiter := rate.NewLimiter(rate.Inf, 0) downloadRateLimiter = rate.NewLimiter(rate.Inf, 0)
uploadRateLimiter := rate.NewLimiter(rate.Inf, 0) uploadRateLimiter = rate.NewLimiter(rate.Inf, 0)
return downloadRateLimiter, uploadRateLimiter return downloadRateLimiter, uploadRateLimiter
} }
@@ -89,17 +92,16 @@ func calculateRateLimiters(uploadRate, downloadRate string) (*rate.Limiter, *rat
downloadRateLimiterSize = 50000 downloadRateLimiterSize = 50000
case "Medium": case "Medium":
downloadRateLimiterSize = 500000 downloadRateLimiterSize = 500000
fmt.Println("Medium Rate Limit...")
case "High": case "High":
downloadRateLimiterSize = 1500000 downloadRateLimiterSize = 1500000
default: default:
downloadRateLimiter := rate.NewLimiter(rate.Inf, 0) downloadRateLimiter = rate.NewLimiter(rate.Inf, 0)
uploadRateLimiter := rate.NewLimiter(rate.Inf, 0) uploadRateLimiter = rate.NewLimiter(rate.Inf, 0)
return downloadRateLimiter, uploadRateLimiter return downloadRateLimiter, uploadRateLimiter
} }
var limitPerSecondUl = rate.Limit(uploadRateLimiterSize) uploadRateLimiter = rate.NewLimiter(rate.Limit(uploadRateLimiterSize), uploadRateLimiterSize)
uploadRateLimiter := rate.NewLimiter(limitPerSecondUl, uploadRateLimiterSize) downloadRateLimiter = rate.NewLimiter(rate.Limit(downloadRateLimiterSize), downloadRateLimiterSize)
var limitPerSecondDl = rate.Limit(uploadRateLimiterSize)
downloadRateLimiter := rate.NewLimiter(limitPerSecondDl, downloadRateLimiterSize)
return downloadRateLimiter, uploadRateLimiter return downloadRateLimiter, uploadRateLimiter
} }
@@ -177,9 +179,9 @@ func FullClientSettingsNew() FullClientSettings {
//Rate Limiters //Rate Limiters
//var uploadRateLimiter *rate.Limiter //var uploadRateLimiter *rate.Limiter
//var downloadRateLimiter *rate.Limiter //var downloadRateLimiter *rate.Limiter
//uploadRate := viper.GetString("serverConfig.UploadRateLimit") uploadRate := viper.GetString("serverConfig.UploadRateLimit")
//downloadRate := viper.GetString("serverConfig.DownloadRateLimit") downloadRate := viper.GetString("serverConfig.DownloadRateLimit")
//downloadRateLimiter, uploadRateLimiter = calculateRateLimiters(uploadRate, downloadRate) downloadRateLimiter, uploadRateLimiter := calculateRateLimiters(uploadRate, downloadRate)
//Internals //Internals
dataDir := filepath.ToSlash(viper.GetString("torrentClientConfig.DownloadDir")) //Converting the string literal into a filepath dataDir := filepath.ToSlash(viper.GetString("torrentClientConfig.DownloadDir")) //Converting the string literal into a filepath
dataDirAbs, err := filepath.Abs(dataDir) //Converting to an absolute file path dataDirAbs, err := filepath.Abs(dataDir) //Converting to an absolute file path
@@ -191,6 +193,7 @@ func FullClientSettingsNew() FullClientSettings {
noDHT := viper.GetBool("torrentClientConfig.NoDHT") noDHT := viper.GetBool("torrentClientConfig.NoDHT")
noUpload := viper.GetBool("torrentClientConfig.NoUpload") noUpload := viper.GetBool("torrentClientConfig.NoUpload")
seed := viper.GetBool("torrentClientConfig.Seed") seed := viper.GetBool("torrentClientConfig.Seed")
maxActiveTorrents := viper.GetInt("serverConfig.MaxActiveTorrents")
peerID := viper.GetString("torrentClientConfig.PeerID") peerID := viper.GetString("torrentClientConfig.PeerID")
disableUTP := viper.GetBool("torrentClientConfig.DisableUTP") disableUTP := viper.GetBool("torrentClientConfig.DisableUTP")
@@ -213,21 +216,21 @@ func FullClientSettingsNew() FullClientSettings {
} }
tConfig := torrent.Config{ tConfig := torrent.Config{
DataDir: dataDirAbs, DataDir: dataDirAbs,
ListenAddr: listenAddr, ListenAddr: listenAddr,
DisablePEX: disablePex, DisablePEX: disablePex,
NoDHT: noDHT, NoDHT: noDHT,
DHTConfig: dhtServerConfig, DHTConfig: dhtServerConfig,
NoUpload: noUpload, NoUpload: noUpload,
Seed: seed, Seed: seed,
//UploadRateLimiter: uploadRateLimiter, UploadRateLimiter: uploadRateLimiter,
//DownloadRateLimiter: downloadRateLimiter, DownloadRateLimiter: downloadRateLimiter,
PeerID: peerID, PeerID: peerID,
DisableUTP: disableUTP, DisableUTP: disableUTP,
DisableTCP: disableTCP, DisableTCP: disableTCP,
DisableIPv6: disableIPv6, DisableIPv6: disableIPv6,
Debug: debug, Debug: debug,
EncryptionPolicy: encryptionPolicy, EncryptionPolicy: encryptionPolicy,
} }
Config := FullClientSettings{ Config := FullClientSettings{
@@ -248,6 +251,7 @@ func FullClientSettingsNew() FullClientSettings {
TorrentConfig: tConfig, TorrentConfig: tConfig,
DefaultMoveFolder: defaultMoveFolderAbs, DefaultMoveFolder: defaultMoveFolderAbs,
TorrentWatchFolder: torrentWatchFolderAbs, TorrentWatchFolder: torrentWatchFolderAbs,
MaxActiveTorrents: maxActiveTorrents,
} }
return Config return Config

View File

@@ -16,6 +16,13 @@ var Logger *logrus.Logger
//Conn is the global websocket connection used to push server notification messages //Conn is the global websocket connection used to push server notification messages
var Conn *websocket.Conn var Conn *websocket.Conn
//TorrentQueues contains the active and queued torrent hashes in slices
type TorrentQueues struct {
ID int `storm:"id,unique"` //storm requires unique ID (will be 5)
ActiveTorrents []string
QueuedTorrents []string
}
//IssuedTokensList contains a slice of all the tokens issues to applications //IssuedTokensList contains a slice of all the tokens issues to applications
type IssuedTokensList struct { type IssuedTokensList struct {
ID int `storm:"id,unique"` //storm requires unique ID (will be 3) to save although there will only be one of these ID int `storm:"id,unique"` //storm requires unique ID (will be 3) to save although there will only be one of these
@@ -94,6 +101,26 @@ func SaveConfig(torrentStorage *storm.DB, config Settings.FullClientSettings) {
} }
} }
//UpdateQueues Saves the slice of hashes that contain the active Torrents
func UpdateQueues(db *storm.DB, torrentQueues TorrentQueues) {
torrentQueues.ID = 5
err := db.Save(&torrentQueues)
if err != nil {
Logger.WithFields(logrus.Fields{"database": db, "error": err}).Error("Unable to write Queues to database!")
}
}
//FetchQueues fetches the activetorrent and queuedtorrent slices from the database
func FetchQueues(db *storm.DB) TorrentQueues {
torrentQueues := TorrentQueues{}
err := db.One("ID", 5, &torrentQueues)
if err != nil {
Logger.WithFields(logrus.Fields{"database": db, "error": err}).Error("Unable to read Database into torrentQueues!")
return torrentQueues
}
return torrentQueues
}
//FetchConfig fetches the client config from the database //FetchConfig fetches the client config from the database
func FetchConfig(torrentStorage *storm.DB) (Settings.FullClientSettings, error) { func FetchConfig(torrentStorage *storm.DB) (Settings.FullClientSettings, error) {
config := Settings.FullClientSettings{} config := Settings.FullClientSettings{}
@@ -166,6 +193,8 @@ func UpdateStorageTick(torrentStorage *storm.DB, torrentLocal TorrentLocal) {
err := torrentStorage.Update(&torrentLocal) err := torrentStorage.Update(&torrentLocal)
if err != nil { if err != nil {
Logger.WithFields(logrus.Fields{"UpdateContents": torrentLocal, "error": err}).Error("Error performing tick update to database!") Logger.WithFields(logrus.Fields{"UpdateContents": torrentLocal, "error": err}).Error("Error performing tick update to database!")
} else {
Logger.WithFields(logrus.Fields{"UpdateContents": torrentLocal, "error": err}).Debug("Performed Update to database!")
} }
} }