1
0
mirror of https://github.com/varbhat/exatorrent.git synced 2021-09-19 22:57:02 +03:00
Files
exatorrent-seedbox-server-cli/internal/core/init.go
Var Bhat a3c79279ab Huge Update
Update Dependencies
Bump Version
Fix tsconfig.json (svelte-preprocess)
Remove unused variables
Fix AddUser
Add `-passw` Flag
2021-09-16 23:42:46 +05:30

334 lines
11 KiB
Go

package core
import (
"bufio"
"encoding/json"
"errors"
"flag"
"fmt"
"io/fs"
"log"
"os"
"os/signal"
"path/filepath"
"syscall"
utp "github.com/anacrolix/go-libutp"
"github.com/anacrolix/torrent"
"github.com/anacrolix/torrent/metainfo"
"github.com/anacrolix/torrent/storage"
"github.com/varbhat/exatorrent/internal/db"
)
func checkDir(dir string) {
fi, err := os.Stat(dir)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
er := os.MkdirAll(dir, 0755)
if er != nil {
Err.Fatalln("Error Creating Directory")
}
return
} else {
Err.Fatalf("Error Stat Directory %s ( %s ) \n", dir, err.Error())
return
}
}
if fi != nil {
if !fi.IsDir() {
Err.Fatalln("Non-Directory File Present")
return
}
} else {
Err.Fatalln("Error Stat Directory ", dir)
}
}
func Initialize() {
var cfilename string
var torcc bool
var psql bool
var engc bool
var err error
var auser string
var pw bool
flag.Usage = func() {
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "exatorrent is bittorrent client\n\n")
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", os.Args[0])
flag.VisitAll(func(f *flag.Flag) {
_, _ = fmt.Fprintf(flag.CommandLine.Output(), " -%-5v %v\n", f.Name, f.Usage)
})
_, _ = fmt.Fprintf(flag.CommandLine.Output(), " -%-5v %v\n", "help", "<opt> Print this Help")
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "\nVersion: %s", Version)
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "\nLicense: GPLv3")
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "\nSource : https://github.com/varbhat/exatorrent\n")
}
flag.StringVar(&Flagconfig.ListenAddress, "addr", ":5000", `<addr> Listen Address (Default: ":5000")`)
flag.StringVar(&Flagconfig.UnixSocket, "unix", "", `<path> Unix Socket Path`)
flag.StringVar(&Flagconfig.TLSKeyPath, "key", "", "<path> Path to TLS Key (Required for HTTPS)")
flag.StringVar(&Flagconfig.TLSCertPath, "cert", "", "<path> Path to TLS Certificate (Required for HTTPS)")
flag.StringVar(&Dirconfig.DirPath, "dir", "exadir", `<path> exatorrent Directory (Default: "exadir")`)
flag.StringVar(&auser, "admin", "adminuser", `<user> Default admin username (Default Username: "adminuser" and Default Password: "adminpassword")`)
flag.BoolVar(&pw, "passw", false, `<opt> Set Default admin password from "EXAPASSWORD" environment variable`)
flag.BoolVar(&psql, "psql", false, "<opt> Generate Sample Postgresql Connection URL")
flag.BoolVar(&engc, "engc", false, "<opt> Generate Custom Engine Configuration")
flag.BoolVar(&torcc, "torc", false, "<opt> Generate Custom Torrent Client Configuration")
flag.Parse()
if len(flag.Args()) != 0 {
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "Invalid Flags Provided: %s\n\n", flag.Args())
flag.Usage()
os.Exit(1)
}
// Display All Flag Configurations Provided to exatorrent
if Flagconfig.UnixSocket != "" {
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "\nUnix Socket Path => %s", Flagconfig.UnixSocket)
} else {
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "\nAddress => %s", Flagconfig.ListenAddress)
}
if Flagconfig.TLSKeyPath != "" {
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "\nTLS Key Path => %s", Flagconfig.TLSKeyPath)
}
if Flagconfig.TLSCertPath != "" {
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "\nTLS Certificate Path => %s", Flagconfig.TLSCertPath)
}
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "\nDirectory => %s\n\n", Dirconfig.DirPath)
// Create Required SubDirectories if not present
checkDir(Dirconfig.DirPath)
Dirconfig.ConfigDir = filepath.Join(Dirconfig.DirPath, "config")
checkDir(Dirconfig.ConfigDir)
Dirconfig.CacheDir = filepath.Join(Dirconfig.DirPath, "cache")
checkDir(Dirconfig.CacheDir)
Dirconfig.DataDir = filepath.Join(Dirconfig.DirPath, "data")
checkDir(Dirconfig.DataDir)
Dirconfig.TrntDir = filepath.Join(Dirconfig.DirPath, "torrents")
checkDir(Dirconfig.TrntDir)
// Load Torrent Client Configuration
cfilename = filepath.Join(Dirconfig.ConfigDir, "clientconfig.json")
_, cfileerr := os.Stat(cfilename)
if cfileerr == nil {
var e error
cf, e := os.Open(cfilename)
if e != nil {
Err.Fatalln("Error Opening ", cfilename)
}
if cf != nil {
e = json.NewDecoder(cf).Decode(&Engine.Tconfig)
if e != nil {
Err.Fatalln("Error Decoding ", cfilename)
}
Info.Println("Torrent Client Configuration is now loaded from ", cfilename)
torcc = true
_ = cf.Close()
}
} else if os.IsNotExist(cfileerr) && torcc {
jfile, _ := json.MarshalIndent(Engine.Tconfig, "", "\t")
_ = os.WriteFile(cfilename, jfile, 0644)
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "\nSample Torrent Client Configuration has been written at %s\n", cfilename)
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "Please Customize Torrent Client Configuration File %s if required , and restart\n", cfilename)
os.Exit(0)
}
// Load Custom Engine Configuration
Engine.Econfig = EngConfig{GlobalSeedRatio: 0, OnlineCacheURL: "https://itorrents.org/torrent/%s.torrent", SRRefresh: 150, TrackerRefresh: 60, TrackerListURLs: []string{"https://ngosang.github.io/trackerslist/trackers_best.txt"}}
// You can also add these "https://newtrackon.com/api/stable" , "https://cdn.jsdelivr.net/gh/XIU2/TrackersListCollection@master/best.txt"
cfilename = filepath.Join(Dirconfig.ConfigDir, "engconfig.json")
_, cfileerr = os.Stat(cfilename)
if cfileerr == nil {
var e error
cf, e := os.Open(cfilename)
if e != nil {
Err.Fatalln("Error Opening ", cfilename)
} else {
if cf != nil {
e = json.NewDecoder(cf).Decode(&Engine.Econfig)
if e != nil {
Err.Fatalln("Error Decoding ", cfilename)
}
Info.Printf("Engine Configuration %+v is now loaded\n", Engine.Econfig)
engc = true
_ = cf.Close()
}
}
} else if os.IsNotExist(cfileerr) && engc {
_ = Engine.Econfig.WriteConfig()
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "\nSample Engine Configuration has been written at %s\n", cfilename)
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "Please Customize Engine Configuration File %s if required , and restart\n", cfilename)
os.Exit(0)
}
// Read Postgresql Secret
cfilename = filepath.Join(Dirconfig.ConfigDir, "psqlconfig.txt")
_, cfileerr = os.Stat(cfilename)
if cfileerr == nil {
pfile, err := os.Open(cfilename)
if err != nil {
Err.Fatalln("Error Reading Postgresql Connection URL: ", err)
}
defer pfile.Close()
scanner := bufio.NewScanner(pfile)
for scanner.Scan() {
Engine.PsqlCon = scanner.Text()
psql = true
Info.Println("Postgresql Connection URL at", cfilename, " has been Read")
break
}
if err := scanner.Err(); err != nil {
Err.Fatalln("Error Reading Postgresql Connection URL: ", err)
}
} else {
Engine.PsqlCon = os.Getenv("DATABASE_URL")
if len(Engine.PsqlCon) != 0 {
psql = true
_ = os.Unsetenv("DATABASE_URL")
}
}
if os.IsNotExist(cfileerr) && psql {
_ = os.WriteFile(cfilename, []byte("postgres://username:password@localhost:5432/database_name"), 0644)
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "\nSample Postgresql Connection URL has been written at %s\n", cfilename)
_, _ = fmt.Fprintf(flag.CommandLine.Output(), "Please Enter your Postgresql Connection URL at File %s , and restart\n", cfilename)
os.Exit(0)
}
tc := Engine.Tconfig.ToTorrentConfig()
// Set Different Logger for UTP
utp.Logger = log.New(os.Stderr, "[UTP ] ", log.LstdFlags) // Info Logger
if psql {
Engine.TorDb = &db.PsqlTrntDb{}
Engine.TorDb.Open(Engine.PsqlCon)
Engine.FsDb = &db.PsqlFsDb{}
Engine.FsDb.Open(Engine.PsqlCon)
Engine.LsDb = &db.PsqlLsDb{}
Engine.LsDb.Open(Engine.PsqlCon)
Engine.UDb = &db.PsqlUserDb{}
Engine.UDb.Open(Engine.PsqlCon)
Engine.TUDb = &db.PsqlTrntUserDb{}
Engine.TUDb.Open(Engine.PsqlCon)
Engine.TrackerDB = &db.PsqlTDb{}
Engine.TrackerDB.Open(Engine.PsqlCon)
Engine.PcDb, err = db.NewPsqlPieceCompletion(Engine.PsqlCon)
if err != nil {
Err.Fatalln("Unable to Connect to Postgresql for PieceCompletion")
}
} else {
sqliteSetup(tc)
}
_, err = os.Stat(filepath.Join(Dirconfig.DataDir, ".adminadded"))
if errors.Is(err, os.ErrNotExist) {
if pw {
Info.Println(`Adding Admin user with username "` + auser + `" and custom password`)
er := Engine.UDb.Add(auser, os.Getenv("EXAPASSWORD"), 1)
if er != nil {
Err.Fatalln("Unable to add admin user to adminless exatorrent instance :", er)
}
_, er = os.Create(filepath.Join(Dirconfig.DataDir, ".adminadded"))
if er != nil {
Err.Fatalln(er)
}
} else {
Info.Println(`Adding Admin user with username "` + auser + `" and password "adminpassword"`)
er := Engine.UDb.Add(auser, "adminpassword", 1)
if er != nil {
Err.Fatalln("Unable to add admin user to adminless exatorrent instance :", er)
}
_, er = os.Create(filepath.Join(Dirconfig.DataDir, ".adminadded"))
if er != nil {
Err.Fatalln(er)
}
}
}
stor := storage.NewFileOpts(storage.NewFileClientOpts{ClientBaseDir: Dirconfig.TrntDir, FilePathMaker: nil, TorrentDirMaker: func(baseDir string, info *metainfo.Info, infoHash metainfo.Hash) string {
return filepath.Join(baseDir, infoHash.HexString())
}, PieceCompletion: Engine.PcDb})
tc.DefaultStorage = stor
Engine.Torc, err = torrent.NewClient(tc)
if err != nil {
Err.Fatalln("Unable to Create Torrent Client ", err)
} else {
Info.Println("Torrent Client Created")
}
go func() {
defer func() {
if err := recover(); err != nil {
Warn.Println(err)
}
}()
var stoperr error
stopsignal := make(chan os.Signal, 5)
signal.Notify(stopsignal, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
sig := <-stopsignal
fmt.Fprintf(os.Stderr, "\n")
Warn.Println("Recieved ", sig)
Warn.Println("Closing exatorrent")
Engine.TorDb.Close()
Engine.TrackerDB.Close()
Engine.TUDb.Close()
stoperr = Engine.PcDb.Close() // Close PcDb at the end
if stoperr != nil {
Warn.Println("Error Closing PieceCompletion DB ", stoperr)
}
Engine.Torc.Close() // Close the Torrent Client
stoperr = stor.Close() // Close the storage.ClientImplCloser
if stoperr != nil {
Warn.Println("Error Closing Default Storage ", stoperr)
}
os.Exit(1)
}()
//Recover Torrents from Database
torlist, err := Engine.TorDb.GetTorrents()
if err != nil {
Err.Fatalln("Error Recovering Torrents")
}
for _, eachtrnt := range torlist {
go func(started bool, infohash metainfo.Hash) {
AddfromSpec("", &torrent.TorrentSpec{InfoHash: infohash}, true, true)
if started {
StartTorrent("", infohash, true)
}
flist := Engine.FsDb.Get(infohash)
if started {
for _, f := range flist {
StopFile("", infohash, f)
}
} else {
for _, f := range flist {
StartFile("", infohash, f)
}
}
}(eachtrnt.Started, eachtrnt.Infohash)
}
go UpdateTrackers()
go TorrentRoutine()
}