Skip to content

Commit

Permalink
first working prototype
Browse files Browse the repository at this point in the history
  • Loading branch information
BruceWangNo1 committed Oct 21, 2017
1 parent fec11bc commit 556d27a
Show file tree
Hide file tree
Showing 6 changed files with 338 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
media
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,21 @@ This repository is an extension to [anacrolix/torrent](https://github.com/anacro

## Installation

Install the library package with `go get github.com/brucewangno1/remote-torrent`.
Install the library package with `go get github.com/brucewangno1/remote-torrent/rt`.

## Commands
## Develpment Enviroment

Here I'll describe what some of the provided commands.
Ubuntu on server side and MacOS on client side.

## Requirement

Install [anacrolix/torrent](https://github.com/anacrolix/torrent) first on your server and wget on your client via brew.

## Command Usage

Server side: `rt server yourPortNumber username:password`
Client side: `rt client username:password yourServerIP:yourServerPortNumber magnetLink`

## Contribution

Looking forward to your contribution.
34 changes: 34 additions & 0 deletions download.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package remote_torrent

import (
"os/exec"
"log"
"bytes"
"fmt"
)

var out bytes.Buffer

func download(magnet string) error {
_, err := exec.LookPath("torrent")
if err != nil {
log.Fatal("Please install anacrolix/torrent first.\n")
return err
}

go func() {
cmd := exec.Command("torrent", magnet)
cmd.Dir = "/root/media/"
cmd.Stdout = &out
err := cmd.Start()
if err != nil {
log.Fatal(err)
return
}
//downloadFinished = make(chan string)
//downloadFinished <- "finished"
fmt.Println("Torrent Download Finished Successfully.")
}()

return nil
}
20 changes: 20 additions & 0 deletions rt/rt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package main

import (
"os"
"log"
rt "github.com/brucewangno1/remote-torrent"
)

// 1) Client Mode (e.g. go run main.go client userName:password ip:port torrentFile/magnetLink)
// 2) Server Mode (e.g. go run main.go server portToListen userName:Password)
func main() {
mode := os.Args[1]
if mode == "client" {
rt.RTClient(os.Args[2:])
} else if mode == "server" {
rt.RTServer(os.Args[2:])
} else {
log.Fatal("Args input is wrong. Please check usage\n")
}
}
151 changes: 151 additions & 0 deletions rtClient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package remote_torrent

import (
"net/http"
"net/url"
"strings"
"fmt"
"io/ioutil"
"time"
"os/exec"
"log"
"os"
)

func RTClient(args []string) {
username := strings.Split(args[0], ":")[0]
password := strings.Split(args[0], ":")[1]
ipAndPort := args[1]
magnet := args[2]

//finished := make(chan error, 2)
//
//c := make(chan os.Signal, 2)
//signal.Notify(c, os.Interrupt, syscall.SIGTERM)
//
//go func() {
// select {
// case <-c:
// if err := cmd.Process.Kill(); err != nil {
// log.Fatal("failed to kill: ", err)
// }
// os.Exit(1)
// return
// case err := <-finished:
// if err != nil {
// fmt.Println(err)
// return
// }
// }
//}()

// schedule torrent download
for {
schedulingResp, err := http.PostForm("http://" + ipAndPort + "/magnet", url.Values{"username": {username}, "password": {password}, "magnet": {magnet}})
if err != nil {
fmt.Println(err)
fmt.Println("retrying...")
continue
} else {
fmt.Println("Torrent download scheduling over http succeeds.")
}

if schedulingResp.StatusCode == http.StatusUnauthorized {
log.Fatal("Authentication failed.")
return
}

body, err := ioutil.ReadAll(schedulingResp.Body)
schedulingResp.Body.Close()

if err != nil {
fmt.Println(err)
fmt.Println("retrying...")
continue
}

fmt.Println(string(body))
break
}

// status check
ticker := time.NewTicker(time.Second * 3)

for range ticker.C {
statusCheckResp, statusCheckErr := http.PostForm("http://" + ipAndPort + "/status", url.Values{"username": {username}, "password": {password}})
if statusCheckErr != nil {
fmt.Println(statusCheckErr)
}

if statusCheckResp.StatusCode == http.StatusUnauthorized {
log.Fatal("Authentication failed.")
return
}

body, err := ioutil.ReadAll(statusCheckResp.Body)
if err != nil {
fmt.Println(err)
}

fmt.Printf("\rStatus check: %s.", string(body))

statusCheckResp.Body.Close()

if strings.Contains(string(body), "Torrent Download Finished.") {
fmt.Println("\nTorrent download completed 100% on server side.")
break
}
}
ticker.Stop()
close(ticker)

// download files from server's directory
for {
_, err := exec.LookPath("wget")
if err != nil {
log.Fatal("Please install wget on your local machine first.\n")
return
}
cmd := exec.Command("wget", "-r", "--post-data", "username=" + username + "&password=" + password, "http://" + ipAndPort + "/")
cmd.Stderr = os.Stdout
err = cmd.Run()
if err != nil {
log.Fatal("Error starting wget: %v", err)
}

//go func() {
// finished <- cmd.Wait()
//}()


fmt.Println("Torrent successfully retrieved to client.")
break
}

// remove torrent on server remotely
for {
removeTorrentResponse, removeTorrentErr := http.PostForm("http://" + ipAndPort + "/remove", url.Values{"username": {username}, "password": {password}})
if removeTorrentErr != nil {
fmt.Println(removeTorrentErr)
fmt.Println("retrying...")
continue
}

if removeTorrentResponse.StatusCode == http.StatusUnauthorized {
log.Fatal("Authentication failed.")
return
}

body, err := ioutil.ReadAll(removeTorrentResponse.Body)
removeTorrentResponse.Body.Close()

if err != nil {
fmt.Println(err)
continue
}
fmt.Println(string(body))
break
}

return
}
116 changes: 116 additions & 0 deletions rtServer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package remote_torrent

import (
"net/http"
"fmt"
"strings"
"os/exec"
"os"
)
var (
port string
username string
password string
//downloadFinished chan string
)

func RTServer(args []string) {
port = args[0]
username = strings.Split(args[1], ":")[0]
password = strings.Split(args[1], ":")[1]

// Simple static webserver
mux := http.NewServeMux()
mux.HandleFunc("/", simpleAuthentication(http.FileServer(http.Dir("/root/media/"))))
mux.HandleFunc("/magnet", torrentDownloadAssignment)
mux.HandleFunc("/status", statusCheck)
mux.HandleFunc("/remove", removeTorrent)
http.ListenAndServe(":"+port, mux)
}


func simpleAuthentication(fn http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
//user, pass, _ := r.BasicAuth()
err := r.ParseForm()
if err != nil {
http.Error(w, "Unauthorized.", 401)
return
}
username := r.PostFormValue("username")
password := r.PostFormValue("password")

if !check(username, password) {
http.Error(w, "Unauthorized.", 401)
return
}
fn.ServeHTTP(w, r)
}
}

func check(u, p string) bool {
if u == username && p == password {
return true
} else {
return false
}
}

func torrentDownloadAssignment(w http.ResponseWriter, r *http.Request) {
if check(r.PostFormValue("username"), r.PostFormValue("password")) {
magnet := r.PostFormValue("magnet")
go download(magnet)
fmt.Fprintf(w, "Torrent Download Scheduled.")
} else {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprintf(w, "Authentication Failed.")
}
}

func statusCheck(w http.ResponseWriter, r *http.Request) {
if check(r.PostFormValue("username"), r.PostFormValue("password")) {
downloadLog := out.String()
if strings.Contains(downloadLog, "utpSocketUtpPacketsReceived") {
fmt.Println("Torrent Download Finished.")
fmt.Fprintf(w, "Torrent Download Finished.")
return
}
info := strings.Split(downloadLog, "% downloading")
infoLength := len(info)
if infoLength < 2 {
fmt.Fprintf(w, "not started yet")
} else {
mostUpToDateStatus := info[infoLength - 2]
mostUpToDateStatusDownloaded := strings.Split(strings.Split(info[infoLength - 1], "(")[1], "/")[0]
mostUpToDateStatusOverallData := strings.Split(strings.Split(info[infoLength - 1], "/")[1], ")")[0]
length := len(mostUpToDateStatus)
statusPercentage := mostUpToDateStatus[length-3:]

fmt.Println(mostUpToDateStatusDownloaded)
fmt.Fprintf(w, statusPercentage + "%% " + mostUpToDateStatusDownloaded + "/"+ mostUpToDateStatusOverallData)
}
} else {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprintf(w, "Authentication Failed.")
}
}

func removeTorrent(w http.ResponseWriter, r *http.Request) {
if check(r.PostFormValue("username"), r.PostFormValue("password")) {
//cmd := exec.Command("bash")
cmd := exec.Command("bash", "-c", "rm -rf /root/media/*")
//cmd.Stdin = strings.NewReader("rm -rf /root/media/*")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout
err := cmd.Run()
if err != nil {
fmt.Println(err)
fmt.Fprintf(w, "'rm' command failed.")
}

fmt.Fprintf(w, "Torrent removed on server side.")
} else {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprintf(w, "Authentication Failed.")
}
}

0 comments on commit 556d27a

Please sign in to comment.