working on pulling settings from file using viper, finished basic RSS feed and cron job

This commit is contained in:
2018-01-10 20:07:00 -05:00
parent 08b3a14576
commit f079a5f067
18 changed files with 30486 additions and 28934 deletions

202
main.go
View File

@@ -13,13 +13,22 @@ import (
"github.com/anacrolix/torrent"
"github.com/asdine/storm"
//"github.com/boltdb/bolt"
Engine "github.com/deranjer/goTorrent/engine"
Storage "github.com/deranjer/goTorrent/storage"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
"github.com/mmcdole/gofeed"
)
//SingleRSSFeedMessage will most likley be deprecated as this is the only way I could get it working currently
type SingleRSSFeedMessage struct { //TODO had issues with getting this to work with Storage or Engine
MessageType string
URL string //the URL of the individual RSS feed
Name string
TotalTorrents int
Torrents []Storage.SingleRSSTorrent //name of the torrentss
}
var (
httpAddr = flag.String("addr", ":8000", "Http server address")
baseTmpl string = "templates/base.tmpl"
@@ -43,14 +52,12 @@ func updateClient(torrentstats []Engine.ClientDB, conn *websocket.Conn) { //get
}
func main() {
//setting up the torrent client
Config := Engine.FullClientSettingsNew() //grabbing from settings.go
os.Mkdir(Config.TFileUploadFolder, os.ModeDir) //creating a directory to store uploaded torrent files
torrentLocalStorage := Storage.TorrentLocal{} //creating a new struct that stores all of our local storage info
fmt.Printf("%+v\n", Config)
//fmt.Printf("%+v\n", Config)
tclient, err := torrent.NewClient(&Config.Config) //pulling out the torrent specific config to use
tclient, err := torrent.NewClient(&Config.TorrentConfig) //pulling out the torrent specific config to use
if err != nil {
log.Fatalf("error creating client: %s", err)
}
@@ -61,14 +68,21 @@ func main() {
}
defer db.Close() //defering closing the database until the program closes
cronEngine := Engine.InitializeCronEngine() //Starting the cron engine for tasks
Engine.RefreshRSSCron(cronEngine, db) // Refresing the RSS feeds on an hourly basis
var TorrentLocalArray = []*Storage.TorrentLocal{} //this is an array of ALL of the local storage torrents, they will be added back in via hash
var RunningTorrentArray = []Engine.ClientDB{} //this stores ALL of the torrents that are running, used for client update pushes combines Local Storage and Running tclient info
var PreviousTorrentArray = []Engine.ClientDB{}
TorrentLocalArray = Storage.ReadInTorrents(db) //pulling in all the already added torrents
if TorrentLocalArray != nil { //the first creation of the running torrent array
RunningTorrentArray = Engine.CreateRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db) //Updates the RunningTorrentArray with the current client data as well
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 func() { //TODO instead of running all torrent fetches in coroutine see if possible to run each single one in a routine so we don't wait for ALL of them to be verified
RunningTorrentArray = Engine.CreateRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db)
}()
//RunningTorrentArray = Engine.CreateRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db) //Updates the RunningTorrentArray with the current client data as well
} else {
fmt.Println("Database is empty!")
@@ -98,7 +112,7 @@ func main() {
fmt.Println("Error adding Torrent from file: ", fileName.Name())
} else {
fmt.Println("Adding Torrent via file", fileName)
Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, Config.DataDir, "file", fileName.Name())
Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, Config.TorrentConfig.DataDir, "file", fileName.Name()) // the starttorrent can take a LONG time on startup
}
})
@@ -121,12 +135,14 @@ func main() {
log.Println("Generic websocket error", err)
return
}
MessageLoop: //Tagging this so we can break out of it with any errors we encounter that are failing
for {
runningTorrents := tclient.Torrents() //getting running torrents here since multiple cases ask for the running torrents
msg := Engine.Message{}
readJSONError := conn.ReadJSON(&msg)
if readJSONError != nil {
fmt.Println("Unable to read JSON client message", err)
break MessageLoop
}
fmt.Println("MessageFull", msg)
@@ -134,7 +150,7 @@ func main() {
case "torrentListRequest":
//fmt.Println("client Requested TorrentList Update")
TorrentLocalArray = Storage.ReadInTorrents(db)
TorrentLocalArray = Storage.ReadInTorrents(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
PreviousTorrentArray = RunningTorrentArray
var torrentlistArray = new(Engine.TorrentList)
@@ -144,43 +160,96 @@ func main() {
//fmt.Println("%+v\n", PreviousTorrentArray)
//fmt.Printf("%+v\n", torrentlistArray)
conn.WriteJSON(torrentlistArray)
break
//updateClient(RunningTorrentArray, conn) // sending the client update information over the websocket
case "torrentFileListRequest": //client requested a filelist update
fmt.Println("client Requested Filelist update")
//fmt.Println("client Requested Filelist update")
FileListArray := Engine.CreateFileListArray(tclient, msg.Payload[0])
conn.WriteJSON(FileListArray) //writing the JSON to the client
break
case "torrentDetailedInfo": //TODO Figure out how to get single torrent info correctly
fmt.Println("client requested detailed Torrent Info")
torrentDetailArray := Engine.CreateTorrentDetailJSON(tclient, msg.Payload[0], db)
conn.WriteJSON(torrentDetailArray)
break
case "torrentPeerListRequest":
fmt.Println("client requested peer list")
torrentPeerList := Engine.CreatePeerListArray(tclient, msg.Payload[0])
//fmt.Printf("%+v\n", torrentPeerList)
//JSONTEST, _ := json.Marshal(torrentPeerList)
//fmt.Println(JSONTEST)
conn.WriteJSON(torrentPeerList)
break
case "rssFeedRequest":
fmt.Println("client requested RSS feed")
RSSList := Storage.FetchRSSFeeds(db)
RSSJSONFeed := Engine.RSSJSONList{MessageType: "rssListRequest", TotalRSSFeeds: len(RSSList.RSSFeeds)}
RSSsingleFeed := Engine.RSSFeedsNames{}
for _, singleFeed := range RSSList.RSSFeeds {
RSSsingleFeed.RSSName = singleFeed.Name
RSSsingleFeed.RSSFeedURL = singleFeed.URL
RSSJSONFeed.RSSFeeds = append(RSSJSONFeed.RSSFeeds, RSSsingleFeed)
}
conn.WriteJSON(RSSJSONFeed)
case "addRSSFeed":
fmt.Println("Adding RSSFeed", msg.Payload[0])
newRSSFeed := msg.Payload[0] //there will only be one RSS feed (hopefully)
fullRSSFeeds := Storage.FetchRSSFeeds(db)
fmt.Println("Pulled full RSS feeds from database: ", fullRSSFeeds)
for _, singleFeed := range fullRSSFeeds.RSSFeeds {
if newRSSFeed == singleFeed.URL || newRSSFeed == "" {
fmt.Println("Empty URL or Duplicate RSS URL to one already in database! Rejecting submission")
break MessageLoop
}
}
fp := gofeed.NewParser()
feed, err := fp.ParseURL(newRSSFeed)
if err != nil {
fmt.Println("Unable to parse the URL as valid RSS.. cannot add RSS...", newRSSFeed)
break MessageLoop
}
fmt.Println("Have feed from URL...", feed.Title)
newRSSFeedFull := Storage.SingleRSSFeed{}
newRSSFeedFull.Name = feed.Title
newRSSFeedFull.URL = msg.Payload[0]
fullRSSFeeds.RSSFeeds = append(fullRSSFeeds.RSSFeeds, newRSSFeedFull) // add the new RSS feed to the stack
Engine.ForceRSSRefresh(db, fullRSSFeeds)
//forcing an RSS refresh to fully populate all rss feeds TODO maybe just push the update of the new RSS feed and leave cron to update? But user would most likely expect and immediate update
case "deleteRSSFeed":
fmt.Println("Deleting RSS Feed", msg.Payload[0])
removingRSSFeed := msg.Payload[0]
Storage.DeleteRSSFeed(db, removingRSSFeed)
fullRSSFeeds := Storage.FetchRSSFeeds(db)
Engine.ForceRSSRefresh(db, fullRSSFeeds)
case "rssTorrentsRequest":
fmt.Println("Requesting Torrent List for feed", msg.Payload[0])
RSSFeedURL := msg.Payload[0]
fullRSSFeeds := Storage.FetchRSSFeeds(db)
for _, singleFeed := range fullRSSFeeds.RSSFeeds {
fmt.Println("URL", singleFeed.URL)
}
UpdatedRSSFeed := Engine.RefreshSingleRSSFeed(db, Storage.FetchSpecificRSSFeed(db, RSSFeedURL))
TorrentRSSList := SingleRSSFeedMessage{MessageType: "rssTorrentList", URL: RSSFeedURL, Name: UpdatedRSSFeed.Name, TotalTorrents: len(UpdatedRSSFeed.Torrents), Torrents: UpdatedRSSFeed.Torrents}
conn.WriteJSON(TorrentRSSList)
case "magnetLinkSubmit": //if we detect a magnet link we will be adding a magnet torrent
clientTorrent, err := tclient.AddMagnet(msg.Payload[0]) //reading the payload into the torrent client
if err != nil {
fmt.Println("Magnet Error", err)
}
fmt.Println(clientTorrent)
fmt.Printf("Adding Magnet Link")
Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, Config.DataDir, "magnet", "") //starting the torrent and creating local DB entry
break
for _, magnetLink := range msg.Payload {
clientTorrent, err := tclient.AddMagnet(magnetLink) //reading the payload into the torrent client
if err != nil {
fmt.Println("Magnet Error could not add torrent! ", err)
break MessageLoop //break out of the loop entirely for this message since we hit an error
}
fmt.Println(clientTorrent)
fmt.Printf("Adding Magnet Link")
Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, Config.TorrentConfig.DataDir, "magnet", "") //starting the torrent and creating local DB entry
}
case "stopTorrents":
TorrentListCommands := msg.Payload
@@ -189,11 +258,15 @@ func main() {
for _, singleSelection := range TorrentListCommands {
if singleTorrent.InfoHash().String() == singleSelection {
fmt.Println("Matched for stopping torrents")
singleTorrent.SetMaxEstablishedConns(0) //Forcing the max amount of connections allowed to zero effectively stopping it
tempTorrentLocal := Storage.TorrentLocal{}
tempTorrentLocal.Hash = singleTorrent.InfoHash().String() //required since this is the ID that stormdb requires
tempTorrentLocal.TorrentStatus = "Stopped"
oldMax := singleTorrent.SetMaxEstablishedConns(0) //Forcing the max amount of connections allowed to zero effectively stopping it
fmt.Println("Setting max connections from ", oldMax, " to 0")
Storage.UpdateStorageTick(db, tempTorrentLocal) //Updating the torrent status
}
}
}
break
case "deleteTorrents":
for _, singleTorrent := range runningTorrents {
@@ -201,12 +274,10 @@ func main() {
for _, singleSelection := range msg.Payload {
if singleTorrent.InfoHash().String() == singleSelection {
fmt.Println("Matched for deleting torrents")
singleTorrent.Drop()
//Storage.DelTorrentLocalStorage(db)
Storage.DelTorrentLocalStorage(db, singleTorrent.InfoHash().String())
}
}
}
break
case "startTorrents":
fmt.Println("Starting torrents", msg.Payload)
@@ -215,11 +286,76 @@ func main() {
for _, singleSelection := range msg.Payload {
if singleTorrent.InfoHash().String() == singleSelection {
fmt.Println("Matched for starting torrents", singleSelection)
singleTorrent.DownloadAll()
tempTorrentLocal := Storage.TorrentLocal{}
tempTorrentLocal.Hash = singleTorrent.InfoHash().String() //required since this is the ID that stormdb requires
tempTorrentLocal.TorrentStatus = "Running" //Setting the status back to running
oldTorrentInfo := Storage.FetchTorrentFromStorage(db, singleTorrent.InfoHash().String()) //Fetching the old max connections setting from the database
if oldTorrentInfo.MaxConnections == 0 { //if somehow the old max was set at zero change it to 80
oldTorrentInfo.MaxConnections = 80
Storage.UpdateStorageTick(db, oldTorrentInfo)
}
oldMax := singleTorrent.SetMaxEstablishedConns(oldTorrentInfo.MaxConnections) //Forcing the max amount of connections allowed to zero effectively stopping it
fmt.Println("Setting max connections from 0 to:", oldMax)
Storage.UpdateStorageTick(db, tempTorrentLocal) //Updating the torrent status
}
}
}
case "setFilePriority": //TODO have one priority second message determines what priority
fmt.Println("Setting file priority", msg.Payload)
priorityRequested := msg.Payload[1] //storing the priority requested
infoHash := msg.Payload[0] //storing our infohash
fileList := append(msg.Payload[:0], msg.Payload[2:]...) //removing the filehash and priority from the array leaving just the filepath
fmt.Println("fileList after stripping out", fileList)
for _, singleTorrent := range runningTorrents {
if singleTorrent.InfoHash().String() == infoHash {
fmt.Println("Matched for changing file prio torrents", singleTorrent)
for _, file := range singleTorrent.Files() {
for _, sentFile := range fileList {
if file.Path() == sentFile {
if priorityRequested == "High" {
fileRead := singleTorrent.NewReader()
fileRead.Seek(file.Offset(), 0)
fileRead.SetReadahead(file.Length())
fmt.Println("Setting priority for HIGH", file.DisplayPath())
activeTorrentStruct := Storage.FetchTorrentFromStorage(db, infoHash) //fetching all the data from the db to update certain fields then write it all back
for i, specificFile := range activeTorrentStruct.TorrentFilePriority { //searching for that specific file
if specificFile.TorrentFilePath == file.DisplayPath() {
activeTorrentStruct.TorrentFilePriority[i].TorrentFilePriority = "High" //writing just that field to the current struct
}
}
Storage.UpdateStorageTick(db, activeTorrentStruct) //rewritting essentially that entire struct right back into the database
}
if priorityRequested == "Normal" {
file.Download()
fmt.Println("Setting priority for Normal", file.DisplayPath())
activeTorrentStruct := Storage.FetchTorrentFromStorage(db, infoHash) //fetching all the data from the db to update certain fields then write it all back
for i, specificFile := range activeTorrentStruct.TorrentFilePriority { //searching for that specific file
if specificFile.TorrentFilePath == file.DisplayPath() {
activeTorrentStruct.TorrentFilePriority[i].TorrentFilePriority = "Normal" //writing just that field to the current struct
}
}
Storage.UpdateStorageTick(db, activeTorrentStruct) //rewritting essentially that entire struct right back into the database
}
if priorityRequested == "Cancel" {
file.Cancel()
fmt.Println("Canceling File", file.DisplayPath())
activeTorrentStruct := Storage.FetchTorrentFromStorage(db, infoHash) //fetching all the data from the db to update certain fields then write it all back
for i, specificFile := range activeTorrentStruct.TorrentFilePriority { //searching for that specific file
if specificFile.TorrentFilePath == file.DisplayPath() {
activeTorrentStruct.TorrentFilePriority[i].TorrentFilePriority = "Canceled" //writing just that field to the current struct
}
}
Storage.UpdateStorageTick(db, activeTorrentStruct) //rewritting essentially that entire struct right back into the database
}
}
}
}
}
}
break
default:
//conn.Close()