Server implementation. (#90)

* Server implementation.

- Share the content of a folder as a magnet file.
- Web interface with all data needed for sharing data.
- New configuration to add several servers
- Every time the content of the server folder is changed, the magnet
file will be generated again.

Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>

* Update dependencies

Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>

* Use boltdb piece completion storage.

Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
This commit is contained in:
Antonio Navarro Perez 2021-11-21 05:03:18 -08:00 committed by GitHub
parent 5d4e48f0f9
commit ddda39b22a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 541 additions and 67 deletions

54
assets/js/servers.js Normal file
View file

@ -0,0 +1,54 @@
Handlebars.registerHelper("to_date", function (timestamp) {
return new Date(timestamp * 1000).toLocaleString()
});
Distribyted.servers = {
_template: null,
_getTemplate: function () {
if (this._template != null) {
return this._template
}
const tTemplate = fetch('/assets/templates/servers.html')
.then((response) => {
if (response.ok) {
return response.text();
} else {
Distribyted.message.error('Error getting data from server. Response: ' + response.status);
}
})
.then((t) => {
return Handlebars.compile(t);
})
.catch(error => {
Distribyted.message.error('Error getting servers template: ' + error.message);
});
this._template = tTemplate;
return tTemplate;
},
_getRoutesJson: function () {
return fetch('/api/servers')
.then(function (response) {
if (response.ok) {
return response.json();
} else {
Distribyted.message.error('Error getting data from server. Response: ' + response.status)
}
})
.catch(function (error) {
Distribyted.message.error('Error getting status info: ' + error.message)
});
},
loadView: function () {
this._getTemplate()
.then(t =>
this._getRoutesJson().then(routes => {
document.getElementById('template_target').innerHTML = t(routes);
})
);
}
}

View file

@ -1,10 +1,9 @@
{{#.}}
<div class="row">
<div class="col-12">
<!-- Recent Order Table -->
<div class="card card-table-border-none">
<div class="card-header justify-content-between">
<h2>{{name}}</h2>
<div class="card-header justify-content-between card-header-border-bottom">
<h2>Route: {{name}}</h2>
</div>
<div class="card-body pt-0 pb-5">
<table class="table card-table table-responsive table-responsive-large" style="width:100%">
@ -13,7 +12,7 @@
<th style="width: 30%">Name</th>
<th style="width: 15%"><i class="mdi mdi-arrow-down"></i> / <i class="mdi mdi-arrow-up"></i>
</th>
<th style="width: 15%">Peers/Seeders</th>
<th style="width: 15%" class="d-none d-lg-table-cell">Peers/Seeders</th>
<th style="width: 35%" class="d-none d-lg-table-cell">Status</th>
<th style="width: 5%" >Actions</th>
</tr>
@ -24,7 +23,7 @@
<td>{{name}}</td>
<td>{{ibytes downloadedBytes timePassed}} / {{ibytes
uploadedBytes timePassed}}</td>
<td>{{{torrent_info peers seeders pieceSize}}}</td>
<td class="d-none d-lg-table-cell">{{{torrent_info peers seeders pieceSize}}}</td>
<td class="d-none d-lg-table-cell">
{{{torrent_status pieceChunks totalPieces}}}
</td>

View file

@ -0,0 +1,45 @@
{{#.}}
<div class="card card-default">
<div class="card-header justify-content-between align-items-center card-header-border-bottom">
<h2>{{name}}</h2>
</div>
<div class="bg-white border rounded">
<div class="row no-gutters">
<div class="col-lg-4 col-xl-3">
<div class="profile-content-left pt-5 pb-3 px-3 px-xl-5">
<div class="contact-info pt-4">
<h5 class="text-dark mb-1">Server Info:</h5>
<p class="text-dark font-weight-medium pt-4 mb-2">State</p>
<p>{{state}}</p>
<p class="text-dark font-weight-medium pt-4 mb-2">Updated At</p>
<p>{{to_date updatedAt}}</p>
<p class="text-dark font-weight-medium pt-4 mb-2">Seeds: {{seeds}}</p>
<p class="text-dark font-weight-medium pt-4 mb-2">Peers: {{peers}}</p>
</div>
</div>
</div>
<div class="col-lg-8 col-xl-9">
<div class="profile-content-right py-5">
<div class="tab-content px-3 px-xl-5">
<div class="mt-5">
<div class="form-group mb-4">
<label for="magnetUri">Magnet URI</label>
<input type="text" class="form-control" id="magnetUri" value="{{magnetUri}}">
<span class="d-block mt-1">Magnet URI pointing to the actual folder content. If content
changes, this URI will change too.</span>
</div>
<div class="form-group mb-4">
<label for="folder">Folder</label>
<input type="folder" class="form-control" id="folder" value="{{folder}}">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{/.}}

View file

@ -121,6 +121,25 @@ func load(configPath string, port, webDAVPort int, fuseAllowOther bool) error {
return fmt.Errorf("error starting torrent client: %w", err)
}
pcp := filepath.Join(conf.Torrent.MetadataFolder, "piece-completion")
if err := os.MkdirAll(pcp, 0744); err != nil {
return fmt.Errorf("error creating piece completion folder: %w", err)
}
pc, err := storage.NewBoltPieceCompletion(pcp)
if err != nil {
return fmt.Errorf("error creating servers piece completion: %w", err)
}
var servers []*torrent.Server
for _, s := range conf.Servers {
server := torrent.NewServer(c, pc, s)
servers = append(servers, server)
if err := server.Start(); err != nil {
return fmt.Errorf("error starting server: %w", err)
}
}
cl := loader.NewConfig(conf.Routes)
ss := torrent.NewStats()
@ -139,6 +158,12 @@ func load(configPath string, port, webDAVPort int, fuseAllowOther bool) error {
go func() {
<-sigChan
log.Info().Msg("closing servers...")
for _, s := range servers {
if err := s.Close(); err != nil {
log.Warn().Err(err).Msg("problem closing server")
}
}
log.Info().Msg("closing items database...")
fis.Close()
log.Info().Msg("closing magnet database...")
@ -189,7 +214,7 @@ func load(configPath string, port, webDAVPort int, fuseAllowOther bool) error {
logFilename := filepath.Join(conf.Log.Path, dlog.FileName)
err = http.New(fc, ss, ts, ch, port, logFilename)
err = http.New(fc, ss, ts, ch, servers, port, logFilename)
log.Error().Err(err).Msg("error initializing HTTP server")
return err
}

View file

@ -12,6 +12,7 @@ const (
metadataFolder = "./distribyted-data/metadata"
mountFolder = "./distribyted-data/mount"
logsFolder = "./distribyted-data/logs"
serverFolder = "./distribyted-data/served-folders/server"
)
func DefaultConfig() *Root {
@ -60,5 +61,34 @@ func DefaultConfig() *Root {
},
},
},
Servers: []*Server{
{
Name: "server",
Path: serverFolder,
Trackers: []string{
"http://p4p.arenabg.com:1337/announce",
"udp://tracker.opentrackr.org:1337/announce",
"udp://9.rarbg.com:2810/announce",
"udp://open.tracker.cl:1337/announce",
"udp://open.stealth.si:80/announce",
"udp://exodus.desync.com:6969/announce",
"http://openbittorrent.com:80/announce",
"udp://www.torrent.eu.org:451/announce",
"udp://vibe.sleepyinternetfun.xyz:1738/announce",
"udp://udp-tracker.shittyurl.org:6969/announce",
"udp://tracker1.bt.moack.co.kr:80/announce",
"udp://tracker0.ufibox.com:6969/announce",
"udp://tracker.zerobytes.xyz:1337/announce",
"udp://tracker.torrent.eu.org:451/announce",
"udp://tracker.tiny-vps.com:6969/announce",
"udp://tracker.theoks.net:6969/announce",
"udp://tracker.pomf.se:80/announce",
"udp://tracker.moeking.me:6969/announce",
"udp://tracker.leech.ie:1337/announce",
"udp://tracker.altrosky.nl:6969/announce",
},
},
},
}
}

View file

@ -8,7 +8,8 @@ type Root struct {
Fuse *FuseGlobal `yaml:"fuse"`
Log *Log `yaml:"log"`
Routes []*Route `yaml:"routes"`
Routes []*Route `yaml:"routes"`
Servers []*Server `yaml:"servers"`
}
type Log struct {
@ -46,6 +47,13 @@ type Route struct {
Torrents []*Torrent `yaml:"torrents"`
}
type Server struct {
Name string `yaml:"name"`
Path string `yaml:"path"`
Trackers []string `yaml:"trackers"`
TrackerURL string `yaml:"tracker_url"`
}
type Torrent struct {
MagnetURI string `yaml:"magnet_uri,omitempty"`
TorrentPath string `yaml:"torrent_path,omitempty"`

7
go.mod
View file

@ -13,12 +13,14 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/dgraph-io/badger/v3 v3.2103.2
github.com/elliotchance/orderedmap v1.4.0 // indirect
github.com/fsnotify/fsnotify v1.5.1
github.com/gin-contrib/static v0.0.1
github.com/gin-gonic/gin v1.7.4
github.com/go-playground/validator/v10 v10.9.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-colorable v0.1.11
github.com/pion/dtls/v2 v2.0.10 // indirect
github.com/pion/mdns v0.0.5 // indirect
github.com/pion/rtp v1.7.4 // indirect
@ -30,8 +32,9 @@ require (
github.com/urfave/cli/v2 v2.3.0
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2
golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02 // indirect
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)
@ -72,7 +75,6 @@ require (
github.com/huandu/xstrings v1.3.2 // indirect
github.com/json-iterator/go v1.1.10 // indirect
github.com/klauspost/compress v1.12.3 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
@ -105,5 +107,4 @@ require (
golang.org/x/text v0.3.6 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
)

50
go.sum
View file

@ -6,6 +6,7 @@ crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
crawshaw.io/sqlite v0.3.3-0.20210127221821-98b1f83c5508 h1:fILCBBFnjnrQ0whVJlGhfv1E/QiaFDNtGFBObEVRnYg=
crawshaw.io/sqlite v0.3.3-0.20210127221821-98b1f83c5508/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@ -20,16 +21,10 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/anacrolix/chansync v0.3.0-0.0.20211007004133-3f72684c4a93 h1:sQ8igc3anitrtKPEHRK+RBvuNZP0+DRAa6jskKlq4+k=
github.com/anacrolix/chansync v0.3.0-0.0.20211007004133-3f72684c4a93/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
github.com/anacrolix/chansync v0.3.0 h1:lRu9tbeuw3wl+PhMu/r+JJCRu5ArFXIluOgdF0ao6/U=
github.com/anacrolix/chansync v0.3.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
github.com/anacrolix/confluence v1.9.0 h1:7WrWktoDw7P4uo1bzgaA8FFesvc7NsTp37sAsG54XlE=
github.com/anacrolix/confluence v1.9.0/go.mod h1:O5uS+WVgip+3SOcV1K7E/jE3m4DtK7Jk6QJTnU2VS5s=
github.com/anacrolix/confluence v1.10.0 h1:xXhz98JUXzJ8223pdMRaVPwG7vrpScEzFzmbT30gCc0=
github.com/anacrolix/confluence v1.10.0/go.mod h1:dEf1nWBXs0AV9w1u8m/UWugPtzgW2nTL7lYZ2cemA/Q=
github.com/anacrolix/dht/v2 v2.10.6-0.20211101005846-41a76066160f h1:YgcXgfOJhrkrhRpLkv0U4zboPvq0ILchLXblCeGg+Eg=
github.com/anacrolix/dht/v2 v2.10.6-0.20211101005846-41a76066160f/go.mod h1:KA6+NFOtJVU1Ix5aKI3L6kTijMXRjNWbaaVokzDbkt8=
github.com/anacrolix/dht/v2 v2.12.1 h1:fvE/JkfDVEHFImsrWCzUsBR/BwyZyLKxZRdUllyAZVU=
github.com/anacrolix/dht/v2 v2.12.1/go.mod h1:GfoiqvbDg0um5RVTJYf5HdPLDgk6TQeWKnPDfQ4bmWw=
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
@ -71,8 +66,6 @@ github.com/anacrolix/sync v0.4.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DC
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
github.com/anacrolix/torrent v1.34.1-0.20211028052123-446016cb270c h1:ghnPwLKrQi8Ji2I09cymzp0ZbIQ57sQaWakBmnuWYSM=
github.com/anacrolix/torrent v1.34.1-0.20211028052123-446016cb270c/go.mod h1:eNmTGUF2tnLB4adDjYgx2+hAZhCYW8r8vjF6ZITO2pU=
github.com/anacrolix/torrent v1.37.0 h1:a6maknK6S0SkVrUUjgtr+w94XSdRM3xXm5mMpYZYhfg=
github.com/anacrolix/torrent v1.37.0/go.mod h1:Z/PwbVgpAthgWLagZoqip84l6XI2NUKr72M+BoF/6vg=
github.com/anacrolix/upnp v0.1.2-0.20200416075019-5e9378ed1425 h1:/Wi6l2ONI1FUFWN4cBwHOO90V4ylp4ud/eov6GUcVFk=
@ -89,7 +82,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/billziss-gh/cgofuse v1.5.0 h1:kH516I/s+Ab4diL/Y/ayFeUjjA8ey+JK12xDfBf4HEs=
github.com/billziss-gh/cgofuse v1.5.0/go.mod h1:LJjoaUojlVjgo5GQoEJTcJNqZJeRU0nCR84CyxKt2YM=
github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bits-and-blooms/bitset v1.2.1 h1:M+/hrU9xlMp7t4TyTDQW97d3tRPVuKFC6zBEK16QnXY=
github.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
@ -99,7 +91,6 @@ github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaq
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@ -137,6 +128,8 @@ github.com/frankban/quicktest v1.9.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9
github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-contrib/static v0.0.1 h1:JVxuvHPuUfkoul12N7dtQw7KRn/pSMq7Ue1Va9Swm1U=
@ -212,7 +205,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@ -261,7 +253,6 @@ github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ic
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
@ -292,21 +283,13 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pion/datachannel v1.4.21 h1:3ZvhNyfmxsAqltQrApLPQMhSFNA+aT87RqyCq4OXmf0=
github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg=
github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E=
github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ=
github.com/pion/dtls/v2 v2.0.9/go.mod h1:O0Wr7si/Zj5/EBFlDzDd6UtVxx25CE1r7XM7BQKYQho=
github.com/pion/dtls/v2 v2.0.10 h1:wgys7gPR1NMbWjmjJ3CW7lkUGaun8djgH8nahpNLnxI=
github.com/pion/dtls/v2 v2.0.10/go.mod h1:00OxfeCRWHShcqT9jx8pKKmBWuTt0NCZoVPCaC4VKvU=
github.com/pion/ice/v2 v2.1.10/go.mod h1:kV4EODVD5ux2z8XncbLHIOtcXKtYXVgLVCeVqnpoeP0=
github.com/pion/ice/v2 v2.1.12 h1:ZDBuZz+fEI7iDifZCYFVzI4p0Foy0YhdSSZ87ZtRcRE=
github.com/pion/ice/v2 v2.1.12/go.mod h1:ovgYHUmwYLlRvcCLI67PnQ5YGe+upXZbGgllBDG/ktU=
github.com/pion/ice/v2 v2.1.13 h1:/YNYcIw56LT/whwuzkTnrprcRnapj2ZNqUsR0W8elmo=
github.com/pion/ice/v2 v2.1.13/go.mod h1:ovgYHUmwYLlRvcCLI67PnQ5YGe+upXZbGgllBDG/ktU=
github.com/pion/interceptor v0.0.13/go.mod h1:svsW2QoLHLoGLUr4pDoSopGBEWk8FZwlfxId/OKRKzo=
github.com/pion/interceptor v0.0.15 h1:pQFkBUL8akUHiGoFr+pM94Q/15x7sLFh0K3Nj+DCC6s=
github.com/pion/interceptor v0.0.15/go.mod h1:pg3J253eGi5bqyKzA74+ej5Y19ez2jkWANVnF+Z9Dfk=
github.com/pion/interceptor v0.1.0 h1:SlXKaDlEvSl7cr4j8fJykzVz4UdH+7UDtcvx+u01wLU=
github.com/pion/interceptor v0.1.0/go.mod h1:j5NIl3tJJPB3u8+Z2Xz8MZs/VV6rc+If9mXEKNuFmEM=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
@ -315,25 +298,17 @@ github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw=
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.6 h1:1zvwBbyd0TeEuuWftrd/4d++m+/kZSeiguxU61LFWpo=
github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
github.com/pion/rtcp v1.2.8 h1:Cys8X6r0xxU65ESTmXkqr8eU1Q1Wx+lNkoZCUH4zD7E=
github.com/pion/rtcp v1.2.8/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.6.5/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.7.0/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.7.2 h1:HCDKDCixh7PVjkQTsqHAbk1lg+bx059EHxcnyl42dYs=
github.com/pion/rtp v1.7.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.7.4 h1:4dMbjb1SuynU5OpA3kz1zHK+u+eOCQjW3MAeVHf1ODA=
github.com/pion/rtp v1.7.4/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
github.com/pion/sctp v1.7.12 h1:GsatLufywVruXbZZT1CKg+Jr8ZTkwiPnmUC/oO9+uuY=
github.com/pion/sctp v1.7.12/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sctp v1.8.0 h1:6erMF2qmQwXr+0iB1lm0AUSmDr9LdmpaBzgSVAEgehw=
github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8=
github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
github.com/pion/srtp/v2 v2.0.2/go.mod h1:VEyLv4CuxrwGY8cxM+Ng3bmVy8ckz/1t6A0q/msKOw0=
github.com/pion/srtp/v2 v2.0.5 h1:ks3wcTvIUE/GHndO3FAvROQ9opy0uLELpwHJaQ1yqhQ=
github.com/pion/srtp/v2 v2.0.5/go.mod h1:8k6AJlal740mrZ6WYxc4Dg6qDqqhxoRG2GSjlUhDF0A=
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
@ -346,8 +321,6 @@ github.com/pion/turn/v2 v2.0.5 h1:iwMHqDfPEDEOFzwWKT56eFmh6DYC6o/+xnLAEzgISbA=
github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw=
github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
github.com/pion/webrtc/v3 v3.0.32 h1:5J+zNep9am8Swh6kEMp+LaGXNvn6qQWpGkLBnVW44L4=
github.com/pion/webrtc/v3 v3.0.32/go.mod h1:wX3V5dQQUGCifhT1mYftC2kCrDQX6ZJ3B7Yad0R9JK0=
github.com/pion/webrtc/v3 v3.1.9 h1:Nyimo16me180ZBT35nV2YcrZvjOs1i4ktUi/UmXVQGg=
github.com/pion/webrtc/v3 v3.1.9/go.mod h1:2b1+xQu7GP0vaMGPLbmEX+uB+Fvn2F4sDBp90ZrPBdI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@ -380,8 +353,6 @@ github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6po
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 h1:Lt9DzQALzHoDwMBGJ6v8ObDPR0dzr2a6sXTB1Fq7IHs=
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.25.0 h1:Rj7XygbUHKUlDPcVdoLyR91fJBsduXj5fRxyqIQj/II=
github.com/rs/zerolog v1.25.0/go.mod h1:7KHcEGe0QZPOm2IE4Kpb5rTh6n1h2hIgS5OOnu1rUaI=
github.com/rs/zerolog v1.26.0 h1:ORM4ibhEZeTeQlCojCK2kPz1ogAY4bGs4tD+SaAdGaE=
github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
@ -439,7 +410,6 @@ github.com/willf/bloom v2.0.3+incompatible/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0s
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
@ -455,7 +425,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
@ -488,12 +457,8 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211005001312-d4b1ae081e3b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211007125505-59d4e928ea9d h1:QWMn1lFvU/nZ58ssWqiFJMd3DKIII8NYc4sn708XgKs=
golang.org/x/net v0.0.0-20211007125505-59d4e928ea9d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@ -533,17 +498,14 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 h1:7zYaz3tjChtpayGDzu6H0hDAUM5zIGA2XW7kRNgQ0jc=
golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02 h1:7NCfEGl0sfUojmX78nK9pBJuUlSZWEJA/TwASvfiPLo=
golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c h1:DHcbWVXeY+0Y8HHKR+rbLwnoh2F4tNCY7rTiHJ30RmA=
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -562,8 +524,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View file

@ -25,6 +25,16 @@ var apiStatusHandler = func(fc *filecache.Cache, ss *torrent.Stats) gin.HandlerF
}
}
var apiServersHandler = func(ss []*torrent.Server) gin.HandlerFunc {
return func(ctx *gin.Context) {
var infos []*torrent.ServerInfo
for _, s := range ss {
infos = append(infos, s.Info())
}
ctx.JSON(http.StatusOK, infos)
}
}
var apiRoutesHandler = func(ss *torrent.Stats) gin.HandlerFunc {
return func(ctx *gin.Context) {
s := ss.RoutesStats()

View file

@ -13,7 +13,7 @@ import (
"github.com/shurcooL/httpfs/html/vfstemplate"
)
func New(fc *filecache.Cache, ss *torrent.Stats, s *torrent.Service, ch *config.Handler, port int, logPath string) error {
func New(fc *filecache.Cache, ss *torrent.Stats, s *torrent.Service, ch *config.Handler, tss []*torrent.Server, port int, logPath string) error {
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.Use(gin.Recovery())
@ -31,11 +31,14 @@ func New(fc *filecache.Cache, ss *torrent.Stats, s *torrent.Service, ch *config.
r.GET("/", indexHandler)
r.GET("/routes", routesHandler(ss))
r.GET("/logs", logsHandler)
r.GET("/servers", serversFoldersHandler())
api := r.Group("/api")
{
api.GET("/log", apiLogHandler(logPath))
api.GET("/status", apiStatusHandler(fc, ss))
api.GET("/servers", apiServersHandler(tss))
api.GET("/routes", apiRoutesHandler(ss))
api.POST("/routes/:route/torrent", apiAddTorrentHandler(s))
api.DELETE("/routes/:route/torrent/:torrent_hash", apiDelTorrentHandler(s))

View file

@ -20,3 +20,9 @@ var routesHandler = func(ss *torrent.Stats) gin.HandlerFunc {
var logsHandler = func(c *gin.Context) {
c.HTML(http.StatusOK, "logs.html", nil)
}
var serversFoldersHandler = func() gin.HandlerFunc {
return func(c *gin.Context) {
c.HTML(http.StatusOK, "servers.html", nil)
}
}

View file

@ -71,4 +71,37 @@ routes:
# torrents:
# - magnet_uri: "magnet:?xt=urn:btih:9dea07ba660a722ae1008c4c8afdd303b6f6e53b&tr=http%3A%2F%2Facademictorrents.com%2Fannounce.php&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969"
# - magnet_uri: "magnet:?xt=urn:btih:d8b3a315172c8d804528762f37fa67db14577cdb&tr=http%3A%2F%2Facademictorrents.com%2Fannounce.php&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969"
# - magnet_uri: "magnet:?xt=urn:btih:1e0a00b9c606cf87c03e676f75929463c7756fb5&tr=http%3A%2F%2Facademictorrents.com%2Fannounce.php&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969"
# - magnet_uri: "magnet:?xt=urn:btih:1e0a00b9c606cf87c03e676f75929463c7756fb5&tr=http%3A%2F%2Facademictorrents.com%2Fannounce.php&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969"
# List of folders where the content will be transformed to a magnet link. You can share any content sending that magnet link to others.
servers:
- name: server
path: ./distribyted-data/served-folders/server
# Get trackers from web text file. The file will be loaded every time a magnet uri is generated,
# so all trackers will be up to date.
# tracker_url: "https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt"
# Trackers to be used to announce the served content. If tracker_url is set and it fails,
# this list will be used instead.
trackers:
- "http://p4p.arenabg.com:1337/announce"
- "udp://tracker.opentrackr.org:1337/announce"
- "udp://9.rarbg.com:2810/announce"
- "udp://open.tracker.cl:1337/announce"
- "udp://open.stealth.si:80/announce"
- "udp://exodus.desync.com:6969/announce"
- "http://openbittorrent.com:80/announce"
- "udp://www.torrent.eu.org:451/announce"
- "udp://vibe.sleepyinternetfun.xyz:1738/announce"
- "udp://udp-tracker.shittyurl.org:6969/announce"
- "udp://tracker1.bt.moack.co.kr:80/announce"
- "udp://tracker0.ufibox.com:6969/announce"
- "udp://tracker.zerobytes.xyz:1337/announce"
- "udp://tracker.torrent.eu.org:451/announce"
- "udp://tracker.tiny-vps.com:6969/announce"
- "udp://tracker.theoks.net:6969/announce"
- "udp://tracker.pomf.se:80/announce"
- "udp://tracker.moeking.me:6969/announce"
- "udp://tracker.leech.ie:1337/announce"
- "udp://tracker.altrosky.nl:6969/announce"

View file

@ -37,6 +37,16 @@
<span class="nav-text">Routes</span>
</a>
</li>
{{if eq . "served-folders"}}
<li class="active">
{{else}}
<li>
{{end}}
<a class="sidenav-item-link" href="/servers">
<i class="mdi mdi-folder-upload-outline"></i>
<span class="nav-text">Served Folders</span>
</a>
</li>
{{if eq . "logs"}}
<li class="active">
{{else}}
@ -47,16 +57,6 @@
<span class="nav-text">Logs</span>
</a>
</li>
<!-- {{if eq . "watched-folders"}}
<li class="active">
{{else}}
<li>
{{end}}
<a class="sidenav-item-link" href="/watched">
<i class="mdi mdi-folder-upload-outline"></i>
<span class="nav-text">Watched Folders</span>
</a>
</li> -->
</ul>
</div>

47
templates/servers.html Normal file
View file

@ -0,0 +1,47 @@
<!DOCTYPE html>
<head>
{{template "header.html" "Served Folders"}}
</head>
<body class="header-fixed sidebar-fixed sidebar-dark header-light" id="body">
<div class="wrapper">
{{template "navbar.html" "served-folders"}}
<div class="page-wrapper">
<!-- Header -->
<header class="main-header " id="header">
<nav class="navbar navbar-static-top navbar-expand-lg">
<!-- Sidebar toggle button -->
<button id="sidebar-toggler" class="sidebar-toggle">
<span class="sr-only">Toggle navigation</span>
</button>
</nav>
</header>
<div class="content-wrapper">
<div class="content" id="template_target">
</div>
<footer class="footer mt-auto">
<div class="copyright bg-white">
</div>
</footer>
</div>
{{template "footer.html"}}
<script src="assets/js/servers.js"></script>
<script>
Distribyted.servers.loadView();
setInterval(function () {
Distribyted.servers.loadView();
}, 5000)
</script>
<script>
</script>
</body>
</html>

253
torrent/server.go Normal file
View file

@ -0,0 +1,253 @@
package torrent
import (
"fmt"
"os"
"path/filepath"
"sync"
"sync/atomic"
"time"
"github.com/anacrolix/torrent"
"github.com/anacrolix/torrent/bencode"
"github.com/anacrolix/torrent/metainfo"
"github.com/anacrolix/torrent/storage"
"github.com/distribyted/distribyted/config"
"github.com/fsnotify/fsnotify"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
type ServerState int
const (
UNKNOWN ServerState = iota
SEEDING
READING
UPDATING
STOPPED
ERROR
)
func (ss ServerState) String() string {
return [...]string{"Unknown", "Seeding", "Reading", "Updating", "Stopped", "Error"}[ss]
}
type ServerInfo struct {
Magnet string `json:"magnetUri"`
UpdatedAt int64 `json:"updatedAt"`
Name string `json:"name"`
Folder string `json:"folder"`
State string `json:"state"`
Peers int `json:"peers"`
Seeds int `json:"seeds"`
}
type Server struct {
cfg *config.Server
log zerolog.Logger
fw *fsnotify.Watcher
eventsCount uint64
c *torrent.Client
pc storage.PieceCompletion
mu sync.RWMutex
t *torrent.Torrent
si ServerInfo
}
func NewServer(c *torrent.Client, pc storage.PieceCompletion, cfg *config.Server) *Server {
l := log.Logger.With().Str("component", "server").Str("name", cfg.Name).Logger()
return &Server{
cfg: cfg,
log: l,
c: c,
pc: pc,
}
}
func (s *Server) Start() error {
s.log.Info().Msg("starting new server folder")
w, err := fsnotify.NewWatcher()
if err != nil {
return err
}
if err := os.MkdirAll(s.cfg.Path, 0744); err != nil {
return fmt.Errorf("error creating server folder: %s. Error: %w", s.cfg.Path, err)
}
if err := filepath.Walk(s.cfg.Path,
func(path string, info os.FileInfo, err error) error {
if info.Mode().IsDir() {
s.log.Debug().Str("folder", path).Msg("adding new folder")
return w.Add(path)
}
return nil
}); err != nil {
return err
}
s.fw = w
if err := s.makeMagnet(); err != nil {
return err
}
go s.watch()
go func() {
for {
select {
case event, ok := <-w.Events:
if !ok {
return
}
s.log.Info().Str("file", event.Name).Str("op", event.Op.String()).Msg("file changed inside server folder")
atomic.AddUint64(&s.eventsCount, 1)
case err, ok := <-w.Errors:
if !ok {
return
}
s.updateState(STOPPED)
s.log.Error().Err(err).Msg("error watching server folder")
}
}
}()
s.log.Info().Msg("server folder started")
return nil
}
func (s *Server) watch() {
s.log.Info().Msg("starting watcher")
for range time.Tick(time.Second * 5) {
if s.eventsCount == 0 {
continue
}
ec := s.eventsCount
if err := s.makeMagnet(); err != nil {
s.updateState(ERROR)
s.log.Error().Err(err).Msg("error generating magnet")
}
atomic.AddUint64(&s.eventsCount, -ec)
}
}
func (s *Server) makeMagnet() error {
s.log.Info().Msg("starting serving new torrent")
info := metainfo.Info{
PieceLength: 1 << 8,
}
s.updateState(READING)
if err := info.BuildFromFilePath(s.cfg.Path); err != nil {
return err
}
s.updateState(UPDATING)
if len(info.Files) == 0 {
s.mu.Lock()
s.si.Magnet = ""
s.si.Folder = s.cfg.Path
s.si.Name = s.cfg.Name
s.si.UpdatedAt = time.Now().Unix()
s.mu.Unlock()
s.log.Info().Msg("not creating magnet from empty folder")
s.updateState(STOPPED)
return nil
}
mi := metainfo.MetaInfo{
InfoBytes: bencode.MustMarshal(info),
}
ih := mi.HashInfoBytes()
to, _ := s.c.AddTorrentOpt(torrent.AddTorrentOpts{
InfoHash: ih,
Storage: storage.NewFileOpts(storage.NewFileClientOpts{
ClientBaseDir: s.cfg.Path,
FilePathMaker: func(opts storage.FilePathMakerOpts) string {
return filepath.Join(opts.File.Path...)
},
TorrentDirMaker: nil,
PieceCompletion: s.pc,
}),
})
tks := s.trackers()
err := to.MergeSpec(&torrent.TorrentSpec{
InfoBytes: mi.InfoBytes,
Trackers: [][]string{tks},
})
if err != nil {
return err
}
m := metainfo.Magnet{
InfoHash: ih,
DisplayName: s.cfg.Name,
Trackers: tks,
}
s.mu.Lock()
s.t = to
s.si.Magnet = m.String()
s.si.Folder = s.cfg.Path
s.si.Name = s.cfg.Name
s.si.UpdatedAt = time.Now().Unix()
s.mu.Unlock()
s.updateState(SEEDING)
s.log.Info().Str("hash", ih.HexString()).Msg("new torrent is ready")
return nil
}
func (s *Server) updateState(ss ServerState) {
s.mu.Lock()
s.si.State = ss.String()
s.mu.Unlock()
}
func (s *Server) trackers() []string {
// TODO load trackers from URL too
return s.cfg.Trackers
}
func (s *Server) Close() error {
if s.fw == nil {
return nil
}
return s.fw.Close()
}
func (s *Server) Info() *ServerInfo {
s.mu.RLock()
defer s.mu.RUnlock()
if s.t != nil {
st := s.t.Stats()
s.si.Peers = st.TotalPeers
s.si.Seeds = st.ConnectedSeeders
}
return &s.si
}