Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
0fdc926cc4 | |||
3280360d47 | |||
f69ec5b9f2 | |||
aee3516682 | |||
a7881a14c7 | |||
128ec774bd | |||
bc612bf5e4 | |||
3f1f9e7104 | |||
eeb6e102f1 | |||
0a0f0cd577 | |||
10399cc6e5 | |||
9363649df0 | |||
a804b401a7 |
@@ -47,26 +47,25 @@ Image of the frontend UI
|
|||||||
|
|
||||||
- [X] Ability to view TOML settings from WebUI (and perhaps change a few as well)
|
- [X] Ability to view TOML settings from WebUI (and perhaps change a few as well)
|
||||||
|
|
||||||
|
- [X] Ability to set priority for individual files (needs more testing!)
|
||||||
|
|
||||||
- [ ] Unit testing completed for a large portion of the package
|
- [ ] Unit testing completed for a large portion of the package
|
||||||
|
|
||||||
- [ ] Stability/bug fixing/Optimization rewrite of some of the core structures of the WebUI and base server
|
- [ ] Stability/bug fixing/Optimization rewrite of some of the core structures of the WebUI and base server
|
||||||
|
|
||||||
- [ ] Put the "Move torrent after download" into own goroutine with checks so the WebUI doesn't freeze when moving torrent
|
- [ ] Put the "Move torrent after download" into own goroutine with checks so the WebUI doesn't freeze when moving torrent
|
||||||
|
|
||||||
- [ ] Ability to set priority for individual files (just added to anacrolix/torrent so coming soon, already added to my UI)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- Late 2018
|
- Late 2018
|
||||||
|
|
||||||
- [ ] Define the websocket API for users to write their own clients/extensions
|
- [X] Define the websocket API for users to write their own clients/extensions
|
||||||
|
|
||||||
- [ ] React-native Android app (I don't own any Mac products so there will be no iPhone version)
|
- [ ] React-native Android app (I don't own any Mac products so there will be no iPhone version)
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
|
|
||||||
All the documentation is available [here](https://deranjer.github.io/)
|
All the documentation is available [here](https://deranjer.github.io/goTorrentDocs/)
|
||||||
|
|
||||||
|
|
||||||
# Special Thanks
|
# Special Thanks
|
||||||
|
122
config.toml.bk
Normal file
122
config.toml.bk
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
[serverConfig]
|
||||||
|
|
||||||
|
ServerPort = ":8000" #leave format as is it expects a string with colon
|
||||||
|
ServerAddr = "192.168.1.8" #Put in the IP address you want to bind to
|
||||||
|
LogLevel = "Info" # Options = Debug, Info, Warn, Error, Fatal, Panic
|
||||||
|
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
|
||||||
|
|
||||||
|
#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
|
||||||
|
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).
|
||||||
|
#Low = ~.05MB/s, Medium = ~.5MB/s, High = ~1.5MB/s
|
||||||
|
UploadRateLimit = "Unlimited" #Options are "Low", "Medium", "High", "Unlimited" #Unlimited is default
|
||||||
|
DownloadRateLimit = "Unlimited"
|
||||||
|
|
||||||
|
[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)
|
||||||
|
WebUIAuth = false # bool, if false no authentication is required for the webUI
|
||||||
|
WebUIUser = "admin"
|
||||||
|
WebUIPassword = "Password1"
|
||||||
|
|
||||||
|
|
||||||
|
[notifications]
|
||||||
|
|
||||||
|
PushBulletToken = "o.8sUHemPkTCaty3u7KnyvEBN19EkeT63g" #add your pushbullet api token here to notify of torrent completion to pushbullet
|
||||||
|
|
||||||
|
[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)
|
||||||
|
ProxyEnabled = false #bool, either false or true
|
||||||
|
#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/"
|
||||||
|
|
||||||
|
[EncryptionPolicy]
|
||||||
|
|
||||||
|
DisableEncryption = false
|
||||||
|
ForceEncryption = false
|
||||||
|
PreferNoEncryption = false
|
||||||
|
|
||||||
|
[torrentClientConfig]
|
||||||
|
DownloadDir = 'downloading' #the full OR relative path where the torrent server stores in-progress torrents
|
||||||
|
|
||||||
|
Seed = false #boolean #seed after download
|
||||||
|
|
||||||
|
# Never send chunks to peers.
|
||||||
|
NoUpload = false #boolean
|
||||||
|
|
||||||
|
#User-provided Client peer ID. If not present, one is generated automatically.
|
||||||
|
PeerID = "" #string
|
||||||
|
|
||||||
|
#The address to listen for new uTP and TCP bittorrent protocol connections. DHT shares a UDP socket with uTP unless configured otherwise.
|
||||||
|
ListenAddr = "" #Leave Blank for default, syntax "HOST:PORT"
|
||||||
|
|
||||||
|
#Don't announce to trackers. This only leaves DHT to discover peers.
|
||||||
|
DisableTrackers = false #boolean
|
||||||
|
|
||||||
|
DisablePEX = false # boolean
|
||||||
|
|
||||||
|
# Don't create a DHT.
|
||||||
|
NoDHT = false #boolean
|
||||||
|
|
||||||
|
#For the bittorrent protocol.
|
||||||
|
DisableUTP = false #bool
|
||||||
|
|
||||||
|
#For the bittorrent protocol.
|
||||||
|
DisableTCP = false #bool
|
||||||
|
|
||||||
|
#Called to instantiate storage for each added torrent. Builtin backends
|
||||||
|
# are in the storage package. If not set, the "file" implementation is used.
|
||||||
|
DefaultStorage = "storage.ClientImpl"
|
||||||
|
|
||||||
|
#encryption policy
|
||||||
|
IPBlocklist = "" #of type iplist.Ranger
|
||||||
|
|
||||||
|
DisableIPv6 = false #boolean
|
||||||
|
|
||||||
|
Debug = false #boolean
|
||||||
|
|
||||||
|
#HTTP *http.Client
|
||||||
|
|
||||||
|
HTTPUserAgent = "" # HTTPUserAgent changes default UserAgent for HTTP requests
|
||||||
|
|
||||||
|
ExtendedHandshakeClientVersion = ""
|
||||||
|
|
||||||
|
Bep20 = ""
|
||||||
|
|
||||||
|
# Overrides the default DHT configuration, see dhtServerConfig #advanced.. so be careful
|
||||||
|
DHTConfig = "" # default is "dht.ServerConfig"
|
||||||
|
|
||||||
|
[dhtServerConfig]
|
||||||
|
# Set NodeId Manually. Caller must ensure that if NodeId does not conform to DHT Security Extensions, that NoSecurity is also set.
|
||||||
|
NodeId = "" #[20]byte
|
||||||
|
|
||||||
|
Conn = "" # https:#godoc.org/net#PacketConn #not implemented
|
||||||
|
|
||||||
|
# Don't respond to queries from other nodes.
|
||||||
|
Passive = false # boolean
|
||||||
|
|
||||||
|
# the default addresses are "router.utorrent.com:6881","router.bittorrent.com:6881","dht.transmissionbt.com:6881","dht.aelitis.com:6881",
|
||||||
|
#https:#github.com/anacrolix/dht/blob/master/dht.go
|
||||||
|
StartingNodes = "dht.GlobalBootstrapAddrs"
|
||||||
|
|
||||||
|
#Disable the DHT security extension: http:#www.libtorrent.org/dht_sec.html.
|
||||||
|
NoSecurity = false
|
||||||
|
|
||||||
|
#Initial IP blocklist to use. Applied before serving and bootstrapping begins.
|
||||||
|
IPBlocklist = "" #of type iplist.Ranger
|
||||||
|
|
||||||
|
#Used to secure the server's ID. Defaults to the Conn's LocalAddr(). Set to the IP that remote nodes will see,
|
||||||
|
#as that IP is what they'll use to validate our ID.
|
||||||
|
PublicIP = "" #net.IP
|
||||||
|
|
||||||
|
#Hook received queries. Return true if you don't want to propagate to the default handlers.
|
||||||
|
OnQuery = "func(query *krpc.Msg, source net.Addr) (propagate bool)"
|
||||||
|
|
||||||
|
#Called when a peer successfully announces to us.
|
||||||
|
OnAnnouncePeer = "func(infoHash metainfo.Hash, peer Peer)"
|
||||||
|
|
||||||
|
#How long to wait before re-sending queries that haven't received a response. Defaults to a random value between 4.5 and 5.5s.
|
||||||
|
QueryResendDelay = "func() time.Duration"
|
@@ -3,7 +3,6 @@ package engine
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/asdine/storm"
|
"github.com/asdine/storm"
|
||||||
Settings "github.com/deranjer/goTorrent/settings"
|
Settings "github.com/deranjer/goTorrent/settings"
|
||||||
@@ -15,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
//MoveAndLeaveSymlink takes the file from the default download dir and moves it to the user specified directory and then leaves a symlink behind.
|
//MoveAndLeaveSymlink takes the file from the default download dir and moves it to the user specified directory and then leaves a symlink behind.
|
||||||
func MoveAndLeaveSymlink(config Settings.FullClientSettings, tHash string, db *storm.DB, moveDone bool, oldPath string) { //moveDone and oldPath are for moving a completed torrent
|
func MoveAndLeaveSymlink(config Settings.FullClientSettings, tHash string, db *storm.DB, moveDone bool, oldPath string) error { //moveDone and oldPath are for moving a completed torrent
|
||||||
tStorage := Storage.FetchTorrentFromStorage(db, tHash)
|
tStorage := Storage.FetchTorrentFromStorage(db, tHash)
|
||||||
Logger.WithFields(logrus.Fields{"Torrent Name": tStorage.TorrentName}).Info("Move and Create symlink started for torrent")
|
Logger.WithFields(logrus.Fields{"Torrent Name": tStorage.TorrentName}).Info("Move and Create symlink started for torrent")
|
||||||
var oldFilePath string
|
var oldFilePath string
|
||||||
@@ -25,6 +24,8 @@ func MoveAndLeaveSymlink(config Settings.FullClientSettings, tHash string, db *s
|
|||||||
oldFilePath, err = filepath.Abs(oldFilePathTemp)
|
oldFilePath, err = filepath.Abs(oldFilePathTemp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.WithFields(logrus.Fields{"Torrent Name": tStorage.TorrentName, "Filepath": oldFilePath}).Error("Cannot create absolute file path!")
|
Logger.WithFields(logrus.Fields{"Torrent Name": tStorage.TorrentName, "Filepath": oldFilePath}).Error("Cannot create absolute file path!")
|
||||||
|
moveDone = false
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
oldFilePathTemp := filepath.Join(config.TorrentConfig.DataDir, tStorage.TorrentName)
|
oldFilePathTemp := filepath.Join(config.TorrentConfig.DataDir, tStorage.TorrentName)
|
||||||
@@ -32,41 +33,58 @@ func MoveAndLeaveSymlink(config Settings.FullClientSettings, tHash string, db *s
|
|||||||
oldFilePath, err = filepath.Abs(oldFilePathTemp)
|
oldFilePath, err = filepath.Abs(oldFilePathTemp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.WithFields(logrus.Fields{"Torrent Name": tStorage.TorrentName, "Filepath": oldFilePath}).Error("Cannot create absolute file path!")
|
Logger.WithFields(logrus.Fields{"Torrent Name": tStorage.TorrentName, "Filepath": oldFilePath}).Error("Cannot create absolute file path!")
|
||||||
|
moveDone = false
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newFilePathTemp := filepath.Join(tStorage.StoragePath, tStorage.TorrentName)
|
newFilePathTemp := filepath.Join(tStorage.StoragePath, tStorage.TorrentName)
|
||||||
newFilePath, err := filepath.Abs(newFilePathTemp)
|
newFilePath, err := filepath.Abs(newFilePathTemp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.WithFields(logrus.Fields{"Torrent Name": tStorage.TorrentName, "Filepath": newFilePath}).Error("Cannot create absolute file path for new file path!")
|
Logger.WithFields(logrus.Fields{"Torrent Name": tStorage.TorrentName, "Filepath": newFilePath}).Error("Cannot create absolute file path for new file path!")
|
||||||
|
moveDone = false
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
_, err = os.Stat(tStorage.StoragePath)
|
_, err = os.Stat(tStorage.StoragePath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
err := os.MkdirAll(tStorage.StoragePath, 0755)
|
err := os.MkdirAll(tStorage.StoragePath, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.WithFields(logrus.Fields{"New File Path": newFilePath, "error": err}).Error("Cannot create new directory")
|
Logger.WithFields(logrus.Fields{"New File Path": newFilePath, "error": err}).Error("Cannot create new directory")
|
||||||
|
moveDone = false
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oldFileInfo, err := os.Stat(oldFilePath)
|
oldFileInfo, err := os.Stat(oldFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.WithFields(logrus.Fields{"Old File info": oldFileInfo, "Old File Path": oldFilePath, "error": err}).Error("Cannot find the old file to copy/symlink!")
|
Logger.WithFields(logrus.Fields{"Old File info": oldFileInfo, "Old File Path": oldFilePath, "error": err}).Error("Cannot find the old file to copy/symlink!")
|
||||||
return
|
moveDone = false
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if oldFilePath != newFilePath {
|
if oldFilePath != newFilePath {
|
||||||
newFilePathDir := filepath.Dir(newFilePath)
|
newFilePathDir := filepath.Dir(newFilePath)
|
||||||
os.Mkdir(newFilePathDir, 0755)
|
os.Mkdir(newFilePathDir, 0777)
|
||||||
err := folderCopy.Copy(oldFilePath, newFilePath) //copy the folder to the new location
|
err := folderCopy.Copy(oldFilePath, newFilePath) //copy the folder to the new location
|
||||||
if err != nil {
|
if err != nil {
|
||||||
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
|
||||||
}
|
}
|
||||||
os.Chmod(newFilePath, 0777)
|
//os.Chmod(newFilePath, 0777)
|
||||||
if runtime.GOOS != "windows" { //TODO the windows symlink is broken on windows 10 creator edition, so on the other platforms create symlink (windows will copy) until Go1.11
|
err = filepath.Walk(newFilePath, func(path string, info os.FileInfo, err error) error { //Walking the file path to change the permissions
|
||||||
|
if err != nil {
|
||||||
|
Logger.WithFields(logrus.Fields{"file": path, "error": err}).Error("Potentially non-critical error, continuing..")
|
||||||
|
}
|
||||||
|
os.Chmod(path, 0777)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
/* if runtime.GOOS != "windows" { //TODO the windows symlink is broken on windows 10 creator edition, so on the other platforms create symlink (windows will copy) until Go1.11
|
||||||
os.RemoveAll(oldFilePath)
|
os.RemoveAll(oldFilePath)
|
||||||
err = os.Symlink(newFilePath, oldFilePath)
|
err = os.Symlink(newFilePath, oldFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath, "error": err}).Error("Error creating symlink")
|
Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath, "error": err}).Error("Error creating symlink")
|
||||||
|
moveDone = false
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
if moveDone == false {
|
if moveDone == false {
|
||||||
tStorage.TorrentMoved = true //TODO error handling instead of just saying torrent was moved when it was not
|
tStorage.TorrentMoved = true //TODO error handling instead of just saying torrent was moved when it was not
|
||||||
notifyUser(tStorage, config, db) //Only notify if we haven't moved yet, don't want to push notify user every time user uses change storage button
|
notifyUser(tStorage, config, db) //Only notify if we haven't moved yet, don't want to push notify user every time user uses change storage button
|
||||||
@@ -75,7 +93,7 @@ func MoveAndLeaveSymlink(config Settings.FullClientSettings, tHash string, db *s
|
|||||||
tStorage.StoragePath = filepath.Dir(newFilePath)
|
tStorage.StoragePath = filepath.Dir(newFilePath)
|
||||||
Storage.UpdateStorageTick(db, tStorage)
|
Storage.UpdateStorageTick(db, tStorage)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func notifyUser(tStorage Storage.TorrentLocal, config Settings.FullClientSettings, db *storm.DB) {
|
func notifyUser(tStorage Storage.TorrentLocal, config Settings.FullClientSettings, db *storm.DB) {
|
||||||
|
@@ -1,47 +0,0 @@
|
|||||||
package engine
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/asdine/storm"
|
|
||||||
Settings "github.com/deranjer/goTorrent/settings"
|
|
||||||
Storage "github.com/deranjer/goTorrent/storage"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMoveAndLeaveSymlink(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
config Settings.FullClientSettings
|
|
||||||
tStorage Storage.TorrentLocal
|
|
||||||
db *storm.DB
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
}{
|
|
||||||
// TODO: Add test cases.
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
MoveAndLeaveSymlink(tt.args.config, tt.args.tStorage, tt.args.db)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_notifyUser(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
tStorage Storage.TorrentLocal
|
|
||||||
config Settings.FullClientSettings
|
|
||||||
db *storm.DB
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
}{
|
|
||||||
// TODO: Add test cases.
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
notifyUser(tt.args.tStorage, tt.args.config, tt.args.db)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@@ -140,7 +140,7 @@ func StartTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage Storage.To
|
|||||||
allStoredTorrents := Storage.FetchAllStoredTorrents(torrentDbStorage)
|
allStoredTorrents := Storage.FetchAllStoredTorrents(torrentDbStorage)
|
||||||
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()}).Error("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")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,8 +184,6 @@ func StartTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage Storage.To
|
|||||||
for _, singleFile := range clientTorrent.Files() { //setting all of the file priorities to normal
|
for _, singleFile := range clientTorrent.Files() { //setting all of the file priorities to normal
|
||||||
singleFile.SetPriority(torrent.PiecePriorityNormal)
|
singleFile.SetPriority(torrent.PiecePriorityNormal)
|
||||||
}
|
}
|
||||||
fmt.Println("Downloading ALL") //starting the download
|
|
||||||
|
|
||||||
CreateServerPushMessage(ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "success", Payload: "Torrent added!"}, Conn)
|
CreateServerPushMessage(ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "success", Payload: "Torrent added!"}, Conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,17 +219,13 @@ func CreateInitialTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto
|
|||||||
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" {
|
if singleTorrentFromStorage.TorrentStatus != "Completed" && singleTorrentFromStorage.TorrentStatus != "Stopped" {
|
||||||
fmt.Println("Starting torrent as download", singleTorrent.Name())
|
|
||||||
singleTorrent.DownloadAll() //set all of the pieces to download (piece prio is NE to file prio)
|
singleTorrent.DownloadAll() //set all of the pieces to download (piece prio is NE to file prio)
|
||||||
NumPieces := singleTorrent.NumPieces() //find the number of pieces
|
NumPieces := singleTorrent.NumPieces() //find the number of pieces
|
||||||
singleTorrent.CancelPieces(1, NumPieces) //cancel all of the pieces to use file priority
|
singleTorrent.CancelPieces(1, NumPieces) //cancel all of the pieces to use file priority
|
||||||
for _, singleFile := range singleTorrent.Files() { //setting all of the file priorities to normal
|
for _, singleFile := range singleTorrent.Files() { //setting all of the file priorities to normal
|
||||||
singleFile.SetPriority(torrent.PiecePriorityNormal)
|
singleFile.SetPriority(torrent.PiecePriorityNormal)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
fmt.Println("Torrent status is....", singleTorrentFromStorage.TorrentStatus)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
SetFilePriority(tclient, db) //Setting the desired file priority from storage
|
SetFilePriority(tclient, db) //Setting the desired file priority from storage
|
||||||
}
|
}
|
||||||
@@ -275,7 +269,19 @@ func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto
|
|||||||
TempHash = singleTorrent.InfoHash()
|
TempHash = singleTorrent.InfoHash()
|
||||||
if (calculatedCompletedSize == singleTorrentFromStorage.TorrentSize) && (singleTorrentFromStorage.TorrentMoved == false) { //if we are done downloading and haven't moved torrent yet
|
if (calculatedCompletedSize == singleTorrentFromStorage.TorrentSize) && (singleTorrentFromStorage.TorrentMoved == false) { //if we are done downloading and haven't moved torrent yet
|
||||||
Logger.WithFields(logrus.Fields{"singleTorrent": singleTorrentFromStorage.TorrentName}).Info("Torrent Completed, moving...")
|
Logger.WithFields(logrus.Fields{"singleTorrent": singleTorrentFromStorage.TorrentName}).Info("Torrent Completed, moving...")
|
||||||
go MoveAndLeaveSymlink(config, singleTorrent.InfoHash().String(), db, false, "") //can take some time to move file so running this in another thread TODO make this a goroutine and skip this block if the routine is still running
|
tStorage := Storage.FetchTorrentFromStorage(db, singleTorrent.InfoHash().String()) //Todo... find a better way to do this in the go-routine currently just to make sure it doesn't trigger multiple times
|
||||||
|
tStorage.TorrentMoved = true
|
||||||
|
Storage.UpdateStorageTick(db, tStorage)
|
||||||
|
go func() { //moving torrent in separate go-routine then verifying that the data is still there and correct
|
||||||
|
err := MoveAndLeaveSymlink(config, singleTorrent.InfoHash().String(), db, false, "") //can take some time to move file so running this in another thread TODO make this a goroutine and skip this block if the routine is still running
|
||||||
|
if err != nil { //If we fail, print the error and attempt a retry
|
||||||
|
Logger.WithFields(logrus.Fields{"singleTorrent": singleTorrentFromStorage.TorrentName, "error": err}).Error("Failed to move Torrent!")
|
||||||
|
VerifyData(singleTorrent)
|
||||||
|
tStorage.TorrentMoved = false
|
||||||
|
Storage.UpdateStorageTick(db, tStorage)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fullStruct := singleTorrent.Stats()
|
fullStruct := singleTorrent.Stats()
|
||||||
|
@@ -23,6 +23,11 @@ func secondsToMinutes(inSeconds int64) string {
|
|||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//VerifyData just verifies the data of a torrent by hash
|
||||||
|
func VerifyData(singleTorrent *torrent.Torrent) {
|
||||||
|
singleTorrent.VerifyData()
|
||||||
|
}
|
||||||
|
|
||||||
//MakeRange creates a range of pieces to set their priority based on a file
|
//MakeRange creates a range of pieces to set their priority based on a file
|
||||||
func MakeRange(min, max int) []int {
|
func MakeRange(min, max int) []int {
|
||||||
a := make([]int, max-min+1)
|
a := make([]int, max-min+1)
|
||||||
@@ -69,7 +74,7 @@ func CopyFile(srcFile string, destFile string) { //TODO move this to our importe
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetFilePriority sets the priorities for all of the files in a torrent
|
//SetFilePriority sets the priorities for all of the files in all of the torrents
|
||||||
func SetFilePriority(t *torrent.Client, db *storm.DB) {
|
func SetFilePriority(t *torrent.Client, db *storm.DB) {
|
||||||
storedTorrents := Storage.FetchAllStoredTorrents(db)
|
storedTorrents := Storage.FetchAllStoredTorrents(db)
|
||||||
for _, singleTorrent := range t.Torrents() {
|
for _, singleTorrent := range t.Torrents() {
|
||||||
|
@@ -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,10 +227,15 @@ 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
|
||||||
webSocketState = false
|
webSocketState = false
|
||||||
@@ -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}),
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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))
|
||||||
|
|
||||||
|
@@ -15,3 +15,4 @@ 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';
|
@@ -130,6 +130,13 @@ const reducer = (state = initialState, action) => {
|
|||||||
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
|
||||||
let buttonStateFinal = state.buttonStateDefault //if no selection dispatch that to redux
|
let buttonStateFinal = state.buttonStateDefault //if no selection dispatch that to redux
|
||||||
|
@@ -136,7 +136,7 @@ class TorrentListTable extends React.Component {
|
|||||||
<TableColumnReordering order={this.state.columnOrder} onOrderChange={this.changeColumnOrder} />
|
<TableColumnReordering order={this.state.columnOrder} onOrderChange={this.changeColumnOrder} />
|
||||||
<IntegratedSelection />
|
<IntegratedSelection />
|
||||||
<TableSelection selectByRowClick highlightSelected showSelectAll />
|
<TableSelection selectByRowClick highlightSelected showSelectAll />
|
||||||
<TableHeaderRow allowSorting allowResizing allowDragging />
|
<TableHeaderRow showSortingControls allowSorting allowResizing allowDragging />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
|
57
main.go
57
main.go
@@ -103,17 +103,18 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Unable to create 'log' folder for logging.... please check permissions.. forcing output to stdout", err)
|
fmt.Println("Unable to create 'log' folder for logging.... please check permissions.. forcing output to stdout", err)
|
||||||
Logger.Out = os.Stdout
|
Logger.Out = os.Stdout
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
os.Remove("logs/server.log") //cleanup the old log on every restart
|
os.Remove("logs/server.log") //cleanup the old log on every restart
|
||||||
file, err := os.OpenFile("logs/server.log", os.O_CREATE|os.O_WRONLY, 0755) //creating the log file
|
file, err := os.OpenFile("logs/server.log", os.O_CREATE|os.O_WRONLY, 0755) //creating the log file
|
||||||
defer file.Close() //TODO.. since we write to this constantly how does close work?
|
//defer file.Close() //TODO.. since we write to this constantly how does close work?
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Unable to create file for logging.... please check permissions.. forcing output to stdout")
|
fmt.Println("Unable to create file for logging.... please check permissions.. forcing output to stdout")
|
||||||
Logger.Out = os.Stdout
|
Logger.Out = os.Stdout
|
||||||
}
|
}
|
||||||
|
fmt.Println("Logging to file logs/server.log")
|
||||||
Logger.Out = file
|
Logger.Out = file
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Logger.Out = os.Stdout
|
Logger.Out = os.Stdout
|
||||||
}
|
}
|
||||||
@@ -264,7 +265,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
|
||||||
@@ -272,27 +273,30 @@ func main() {
|
|||||||
|
|
||||||
case "torrentListRequest":
|
case "torrentListRequest":
|
||||||
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
|
||||||
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 th 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)}
|
||||||
Logger.WithFields(logrus.Fields{"torrentList": torrentlistArray, "previousTorrentList": PreviousTorrentArray}).Debug("Previous and Current Torrent Lists for sending to client")
|
Logger.WithFields(logrus.Fields{"torrentList": torrentlistArray, "previousTorrentList": PreviousTorrentArray}).Debug("Previous and Current Torrent Lists for sending to client")
|
||||||
conn.WriteJSON(torrentlistArray)
|
conn.WriteJSON(torrentlistArray)
|
||||||
|
}()
|
||||||
|
|
||||||
case "torrentFileListRequest": //client requested a filelist update
|
case "torrentFileListRequest": //client requested a filelist update
|
||||||
Logger.WithFields(logrus.Fields{"message": msg}).Debug("Client Requested FileList Update")
|
Logger.WithFields(logrus.Fields{"message": msg}).Info("Client Requested FileList Update")
|
||||||
fileListArrayRequest := payloadData["FileListHash"].(string)
|
fileListArrayRequest := payloadData["FileListHash"].(string)
|
||||||
FileListArray := Engine.CreateFileListArray(tclient, fileListArrayRequest, db, Config)
|
FileListArray := Engine.CreateFileListArray(tclient, fileListArrayRequest, db, Config)
|
||||||
conn.WriteJSON(FileListArray) //writing the JSON to the client
|
conn.WriteJSON(FileListArray) //writing the JSON to the client
|
||||||
|
|
||||||
case "torrentPeerListRequest":
|
case "torrentPeerListRequest":
|
||||||
Logger.WithFields(logrus.Fields{"message": msg}).Debug("Client Requested PeerList Update")
|
Logger.WithFields(logrus.Fields{"message": msg}).Info("Client Requested PeerList Update")
|
||||||
peerListArrayRequest := payloadData["PeerListHash"].(string)
|
peerListArrayRequest := payloadData["PeerListHash"].(string)
|
||||||
torrentPeerList := Engine.CreatePeerListArray(tclient, peerListArrayRequest)
|
torrentPeerList := Engine.CreatePeerListArray(tclient, peerListArrayRequest)
|
||||||
conn.WriteJSON(torrentPeerList)
|
conn.WriteJSON(torrentPeerList)
|
||||||
|
|
||||||
case "fetchTorrentsByLabel": //TODO test this to make sure it works
|
case "fetchTorrentsByLabel":
|
||||||
Logger.WithFields(logrus.Fields{"message": msg}).Debug("Client Requested Torrents by Label")
|
Logger.WithFields(logrus.Fields{"message": msg}).Info("Client Requested Torrents by Label")
|
||||||
label := payloadData["Label"].(string)
|
label := payloadData["Label"].(string)
|
||||||
torrentsByLabel := Storage.FetchTorrentsByLabel(db, label)
|
torrentsByLabel := Storage.FetchTorrentsByLabel(db, label)
|
||||||
RunningTorrentArray = Engine.CreateRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db)
|
RunningTorrentArray = Engine.CreateRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db)
|
||||||
@@ -307,7 +311,7 @@ func main() {
|
|||||||
conn.WriteJSON(labelRunningArray)
|
conn.WriteJSON(labelRunningArray)
|
||||||
|
|
||||||
case "changeStorageValue":
|
case "changeStorageValue":
|
||||||
Logger.WithFields(logrus.Fields{"message": msg}).Debug("Client Requested Storage Location Update")
|
Logger.WithFields(logrus.Fields{"message": msg}).Info("Client Requested Storage Location Update")
|
||||||
newStorageLocation := payloadData["StorageValue"].(string)
|
newStorageLocation := payloadData["StorageValue"].(string)
|
||||||
hashes := payloadData["ChangeStorageHashes"].([]interface{})
|
hashes := payloadData["ChangeStorageHashes"].([]interface{})
|
||||||
for _, singleHash := range hashes {
|
for _, singleHash := range hashes {
|
||||||
@@ -328,12 +332,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "settingsFileRequest":
|
case "settingsFileRequest":
|
||||||
Logger.WithFields(logrus.Fields{"message": msg}).Debug("Client Requested Settings File")
|
Logger.WithFields(logrus.Fields{"message": msg}).Info("Client Requested Settings File")
|
||||||
clientSettingsFile := Engine.SettingsFile{MessageType: "settingsFile", Config: Config}
|
clientSettingsFile := Engine.SettingsFile{MessageType: "settingsFile", Config: Config}
|
||||||
conn.WriteJSON(clientSettingsFile)
|
conn.WriteJSON(clientSettingsFile)
|
||||||
|
|
||||||
case "rssFeedRequest":
|
case "rssFeedRequest":
|
||||||
Logger.WithFields(logrus.Fields{"message": msg}).Debug("Client Requested RSS Update")
|
Logger.WithFields(logrus.Fields{"message": msg}).Info("Client Requested RSS Update")
|
||||||
RSSList := Storage.FetchRSSFeeds(db)
|
RSSList := Storage.FetchRSSFeeds(db)
|
||||||
RSSJSONFeed := Engine.RSSJSONList{MessageType: "rssList", TotalRSSFeeds: len(RSSList.RSSFeeds)}
|
RSSJSONFeed := Engine.RSSJSONList{MessageType: "rssList", TotalRSSFeeds: len(RSSList.RSSFeeds)}
|
||||||
RSSsingleFeed := Engine.RSSFeedsNames{}
|
RSSsingleFeed := Engine.RSSFeedsNames{}
|
||||||
@@ -346,9 +350,9 @@ func main() {
|
|||||||
|
|
||||||
case "addRSSFeed":
|
case "addRSSFeed":
|
||||||
newRSSFeed := payloadData["RSSURL"].(string)
|
newRSSFeed := payloadData["RSSURL"].(string)
|
||||||
Logger.WithFields(logrus.Fields{"message": newRSSFeed}).Debug("Client Added RSS Feed")
|
Logger.WithFields(logrus.Fields{"message": newRSSFeed}).Info("Client Added RSS Feed")
|
||||||
fullRSSFeeds := Storage.FetchRSSFeeds(db)
|
fullRSSFeeds := Storage.FetchRSSFeeds(db)
|
||||||
Logger.WithFields(logrus.Fields{"RSSFeeds": fullRSSFeeds}).Debug("Pulled Full RSS Feeds")
|
Logger.WithFields(logrus.Fields{"RSSFeeds": fullRSSFeeds}).Info("Pulled Full RSS Feeds")
|
||||||
for _, singleFeed := range fullRSSFeeds.RSSFeeds {
|
for _, singleFeed := range fullRSSFeeds.RSSFeeds {
|
||||||
if newRSSFeed == singleFeed.URL || newRSSFeed == "" {
|
if newRSSFeed == singleFeed.URL || newRSSFeed == "" {
|
||||||
Logger.WithFields(logrus.Fields{"RSSFeed": newRSSFeed}).Warn("Empty URL or Duplicate RSS URL to one already in database! Rejecting submission")
|
Logger.WithFields(logrus.Fields{"RSSFeed": newRSSFeed}).Warn("Empty URL or Duplicate RSS URL to one already in database! Rejecting submission")
|
||||||
@@ -375,7 +379,7 @@ func main() {
|
|||||||
|
|
||||||
case "deleteRSSFeed":
|
case "deleteRSSFeed":
|
||||||
deleteRSSFeed := payloadData["RSSURL"].(string)
|
deleteRSSFeed := payloadData["RSSURL"].(string)
|
||||||
Logger.WithFields(logrus.Fields{"message": deleteRSSFeed}).Debug("Deleting RSS Feed")
|
Logger.WithFields(logrus.Fields{"message": deleteRSSFeed}).Info("Deleting RSS Feed")
|
||||||
Storage.DeleteRSSFeed(db, deleteRSSFeed)
|
Storage.DeleteRSSFeed(db, deleteRSSFeed)
|
||||||
fullRSSFeeds := Storage.FetchRSSFeeds(db)
|
fullRSSFeeds := Storage.FetchRSSFeeds(db)
|
||||||
Engine.CreateServerPushMessage(Engine.ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "info", Payload: "Deleting RSS feed..."}, conn)
|
Engine.CreateServerPushMessage(Engine.ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "info", Payload: "Deleting RSS feed..."}, conn)
|
||||||
@@ -386,7 +390,7 @@ func main() {
|
|||||||
Logger.WithFields(logrus.Fields{"RSSFeed": RSSFeedURL}).Info("Requesting torrentList for feed..")
|
Logger.WithFields(logrus.Fields{"RSSFeed": RSSFeedURL}).Info("Requesting torrentList for feed..")
|
||||||
UpdatedRSSFeed := Engine.RefreshSingleRSSFeed(db, Storage.FetchSpecificRSSFeed(db, RSSFeedURL))
|
UpdatedRSSFeed := Engine.RefreshSingleRSSFeed(db, Storage.FetchSpecificRSSFeed(db, RSSFeedURL))
|
||||||
TorrentRSSList := Engine.SingleRSSFeedMessage{MessageType: "rssTorrentList", URL: RSSFeedURL, Name: UpdatedRSSFeed.Name, TotalTorrents: len(UpdatedRSSFeed.Torrents), Torrents: UpdatedRSSFeed.Torrents}
|
TorrentRSSList := Engine.SingleRSSFeedMessage{MessageType: "rssTorrentList", URL: RSSFeedURL, Name: UpdatedRSSFeed.Name, TotalTorrents: len(UpdatedRSSFeed.Torrents), Torrents: UpdatedRSSFeed.Torrents}
|
||||||
Logger.WithFields(logrus.Fields{"TorrentRSSList": TorrentRSSList}).Debug("Returning Torrent list from RSSFeed to client")
|
Logger.WithFields(logrus.Fields{"TorrentRSSList": TorrentRSSList}).Info("Returning Torrent list from RSSFeed to client")
|
||||||
conn.WriteJSON(TorrentRSSList)
|
conn.WriteJSON(TorrentRSSList)
|
||||||
|
|
||||||
case "magnetLinkSubmit": //if we detect a magnet link we will be adding a magnet torrent
|
case "magnetLinkSubmit": //if we detect a magnet link we will be adding a magnet torrent
|
||||||
@@ -418,7 +422,7 @@ 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)
|
||||||
Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, "magnet", "", storageValue, labelValue, Config) //starting the torrent and creating local DB entry
|
go Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, "magnet", "", storageValue, labelValue, Config) //starting the torrent and creating local DB entry
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +469,7 @@ 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")
|
||||||
Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, "file", filePathAbs, storageValue, labelValue, Config)
|
go Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, "file", filePathAbs, storageValue, labelValue, Config)
|
||||||
|
|
||||||
case "stopTorrents":
|
case "stopTorrents":
|
||||||
torrentHashes := payloadData["TorrentHashes"].([]interface{})
|
torrentHashes := payloadData["TorrentHashes"].([]interface{})
|
||||||
@@ -509,10 +513,29 @@ func main() {
|
|||||||
for _, singleTorrent := range runningTorrents {
|
for _, singleTorrent := range runningTorrents {
|
||||||
for _, singleSelection := range torrentHashes {
|
for _, singleSelection := range torrentHashes {
|
||||||
if singleTorrent.InfoHash().String() == singleSelection {
|
if singleTorrent.InfoHash().String() == singleSelection {
|
||||||
Logger.WithFields(logrus.Fields{"infoHash": singleTorrent.InfoHash().String()}).Debug("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"
|
oldTorrentInfo.TorrentStatus = "Running"
|
||||||
oldTorrentInfo.MaxConnections = 80
|
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
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user