Compare commits

...
Author SHA1 Message Date
Ben 0bed02ed73 trying to get back tracker stats 2024-09-18 12:21:45 +02:00
Ben d03dd9f954 improvements 2024-09-18 12:08:10 +02:00
Ben 9d5abd8955 getting closer 2024-09-17 16:03:58 +02:00
Ben 5b53c1af03 All lined up 2024-09-17 13:44:06 +02:00
Ben 125ee5d22e moves to correct folders 2024-09-17 10:50:52 +02:00
Ben 65da61823a setup 2024-09-17 10:46:38 +02:00
31 changed files with 828 additions and 15 deletions
+11
View File
@@ -16,6 +16,7 @@ namespace Core
TResponse HttpPostString<TResponse>(string route, string body);
string HttpPostStream(string route, Stream stream);
Stream HttpGetStream(string route);
string HttpPutString(string route, string body);
T Deserialize<T>(string json);
}
@@ -114,6 +115,16 @@ namespace Core
}, $"HTTP-GET-STREAM: {route}");
}
public string HttpPutString(string route, string body)
{
return http.OnClient(client =>
{
var response = Time.Wait(client.PutAsync(GetUrl() + route,
new StringContent(body, MediaTypeHeaderValue.Parse("application/json"))));
return Time.Wait(response.Content.ReadAsStringAsync());
}, $"HTTP-PUT-STR: {route}");
}
public T Deserialize<T>(string json)
{
var errors = new List<string>();
+9 -2
View File
@@ -31,9 +31,16 @@ namespace FileUtils
public const int ChunkSize = 1024 * 1024 * 100;
public FileManager(ILog log, string rootFolder)
public FileManager(ILog log, string rootFolder, bool numberSubfolders = true)
{
folder = Path.Combine(rootFolder, folderNumberSource.GetNextNumber().ToString("D5"));
if (numberSubfolders)
{
folder = Path.Combine(rootFolder, folderNumberSource.GetNextNumber().ToString("D5"));
}
else
{
folder = rootFolder;
}
this.log = log;
}
@@ -170,7 +170,7 @@ namespace KubernetesWorkflow
var addresses = CreateContainerAddresses(startResult, r);
log.Debug($"{r}={name} -> container addresses: {string.Join(Environment.NewLine, addresses.Select(a => a.ToString()))}");
return new RunningContainer(Guid.NewGuid().ToString(), name, r, addresses);
return new RunningContainer(log, Guid.NewGuid().ToString(), name, r, addresses);
}).ToArray();
}
@@ -7,8 +7,11 @@ namespace KubernetesWorkflow.Types
{
public class RunningContainer
{
public RunningContainer(string id, string name, ContainerRecipe recipe, ContainerAddress[] addresses)
private readonly ILog log;
public RunningContainer(ILog log, string id, string name, ContainerRecipe recipe, ContainerAddress[] addresses)
{
this.log = log;
Id = id;
Name = name;
Recipe = recipe;
@@ -24,7 +27,7 @@ namespace KubernetesWorkflow.Types
[JsonIgnore]
public RunningPod RunningPod { get; internal set; } = null!;
public Address GetAddress(ILog log, string portTag)
public Address GetAddress(string portTag)
{
var addresses = Addresses.Where(a => a.PortTag == portTag).ToArray();
if (!addresses.Any()) throw new Exception("No addresses found for portTag: " + portTag);
@@ -0,0 +1,22 @@
using KubernetesWorkflow;
using KubernetesWorkflow.Recipe;
namespace BittorrentPlugin
{
public class BittorrentContainerRecipe : ContainerRecipeFactory
{
public override string AppName => "bittorrent";
public override string Image => "thatbenbierens/bittorrentdriver:init12";
public static string ApiPortTag = "API_PORT";
public static string TrackerPortTag = "TRACKER_PORT";
public static string PeerPortTag = "PEER_PORT";
protected override void Initialize(StartupConfig config)
{
AddInternalPortAndVar("TRACKERPORT", TrackerPortTag);
AddInternalPortAndVar("PEERPORT", PeerPortTag);
AddExposedPortAndVar("APIPORT", ApiPortTag);
}
}
}
@@ -0,0 +1,146 @@
using Core;
using KubernetesWorkflow.Types;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Utils;
namespace BittorrentPlugin
{
public interface IBittorrentNode
{
string StartAsTracker();
string AddTracker(IBittorrentNode tracker, string localFile);
string PutFile(string base64);
string GetTrackerStats();
CreateTorrentResult CreateTorrent(ByteSize size, IBittorrentNode tracker);
string StartDaemon();
string DownloadTorrent(string LocalFile);
}
public class BittorrentNode : IBittorrentNode
{
private readonly IPluginTools tools;
private readonly RunningContainer container;
private readonly PodInfo podInfo;
public BittorrentNode(IPluginTools tools, RunningContainer container)
{
this.tools = tools;
this.container = container;
podInfo = tools.CreateWorkflow().GetPodInfo(container);
}
public string StartAsTracker()
{
//TrackerAddress = container.GetInternalAddress(BittorrentContainerRecipe.TrackerPortTag);
var endpoint = GetEndpoint();
return endpoint.HttpPutString("starttracker", GetTrackerAddress().Port.ToString());
}
public string AddTracker(IBittorrentNode tracker, string localFile)
{
var endpoint = GetEndpoint();
var trackerUrl = ((BittorrentNode)tracker).GetTrackerAddress();
return endpoint.HttpPostJson("addtracker", new AddTrackerRequest
{
LocalFile = localFile,
TrackerUrl = $"{trackerUrl}/announce"
});
}
public string PutFile(string base64)
{
var endpoint = GetEndpoint();
return endpoint.HttpPostJson("postfile", new PostFileRequest
{
Base64Content = base64
});
}
public string StartDaemon()
{
var endpoint = GetEndpoint();
var peerPortAddress = container.GetInternalAddress(BittorrentContainerRecipe.PeerPortTag);
return endpoint.HttpPutString("daemon", peerPortAddress.Port.ToString());
}
public CreateTorrentResult CreateTorrent(ByteSize size, IBittorrentNode tracker)
{
var trackerUrl = ((BittorrentNode)tracker).GetTrackerAddress();
var endpoint = GetEndpoint();
var json = endpoint.HttpPostJson("create", new CreateTorrentRequest
{
Size = Convert.ToInt32(size.SizeInBytes),
TrackerUrl = $"{trackerUrl}/announce"
});
return JsonConvert.DeserializeObject<CreateTorrentResult>(json)!;
}
public string DownloadTorrent(string localFile)
{
var endpoint = GetEndpoint();
return endpoint.HttpPostJson("download", new DownloadTorrentRequest
{
LocalFile = localFile
});
}
public string GetTrackerStats()
{
var endpoint = GetEndpoint();
return endpoint.HttpGetString("stats");
}
//public Address TrackerAddress { get; private set; } = new Address("", 0);
public Address GetTrackerAddress()
{
var address = container.GetInternalAddress(BittorrentContainerRecipe.TrackerPortTag);
return new Address("http://" + podInfo.Ip, address.Port);
}
private IEndpoint GetEndpoint()
{
var address = container.GetAddress(BittorrentContainerRecipe.ApiPortTag);
var http = tools.CreateHttp(address.ToString(), c => { });
return http.CreateEndpoint(address, "/torrent/", container.Name);
}
}
public class CreateTorrentRequest
{
public int Size { get; set; }
public string TrackerUrl { get; set; } = string.Empty;
}
public class CreateTorrentResult
{
public string LocalFilePath { get; set; } = string.Empty;
public string TorrentBase64 { get; set; } = string.Empty;
}
public class DownloadTorrentRequest
{
public string LocalFile { get; set; } = string.Empty;
}
public class AddTrackerRequest
{
public string TrackerUrl { get; set; } = string.Empty;
public string LocalFile { get; set; } = string.Empty;
}
public class PostFileRequest
{
public string Base64Content { get; set; } = string.Empty;
}
}
@@ -0,0 +1,34 @@
using Core;
using KubernetesWorkflow;
using KubernetesWorkflow.Recipe;
namespace BittorrentPlugin
{
public class BittorrentPlugin : IProjectPlugin
{
private readonly IPluginTools tools;
public BittorrentPlugin(IPluginTools tools)
{
this.tools = tools;
}
public void Announce()
{
tools.GetLog().Log("Loaded Bittorrent plugin");
}
public void Decommission()
{
}
public IBittorrentNode StartNode()
{
var flow = tools.CreateWorkflow();
var pod = flow.Start(1, new BittorrentContainerRecipe(), new StartupConfig()).WaitForOnline();
var container = pod.Containers.Single();
return new BittorrentNode(tools, container);
}
}
}
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Framework\Core\Core.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
using Core;
namespace BittorrentPlugin
{
public static class CoreInterfaceExtensions
{
public static IBittorrentNode StartBittorrentNode(this CoreInterface ci)
{
return Plugin(ci).StartNode();
}
private static BittorrentPlugin Plugin(CoreInterface ci)
{
return ci.GetPlugin<BittorrentPlugin>();
}
}
}
@@ -19,7 +19,7 @@ namespace CodexContractsPlugin
{
var config = startupConfig.Get<CodexContractsContainerConfig>();
var address = config.GethNode.StartResult.Container.GetAddress(new NullLog(), GethContainerRecipe.HttpPortTag);
var address = config.GethNode.StartResult.Container.GetAddress(GethContainerRecipe.HttpPortTag);
SetSchedulingAffinity(notIn: "false");
+1 -1
View File
@@ -189,7 +189,7 @@ namespace CodexPlugin
private Address GetAddress()
{
return Container.Containers.Single().GetAddress(log, CodexContainerRecipe.ApiPortTag);
return Container.Containers.Single().GetAddress(CodexContainerRecipe.ApiPortTag);
}
private string GetHttpId()
+1 -1
View File
@@ -57,7 +57,7 @@ namespace GethPlugin
protected override NethereumInteraction StartInteraction()
{
var address = StartResult.Container.GetAddress(log, GethContainerRecipe.HttpPortTag);
var address = StartResult.Container.GetAddress(GethContainerRecipe.HttpPortTag);
var account = StartResult.Account;
var creator = new NethereumInteractionCreator(log, address.Host, address.Port, account.PrivateKey);
+2 -2
View File
@@ -15,7 +15,7 @@ namespace MetricsPlugin
{
RunningContainer = runningContainer;
log = tools.GetLog();
var address = RunningContainer.GetAddress(log, PrometheusContainerRecipe.PortTag);
var address = RunningContainer.GetAddress(PrometheusContainerRecipe.PortTag);
endpoint = tools
.CreateHttp(address.ToString())
.CreateEndpoint(address, "/api/v1/");
@@ -126,7 +126,7 @@ namespace MetricsPlugin
private string GetInstanceNameForNode(IMetricsScrapeTarget target)
{
return ScrapeTargetHelper.FormatTarget(log, target);
return ScrapeTargetHelper.FormatTarget(target);
}
private string GetInstanceStringForNode(IMetricsScrapeTarget target)
@@ -72,15 +72,15 @@ namespace MetricsPlugin
private string FormatTarget(IMetricsScrapeTarget target)
{
return ScrapeTargetHelper.FormatTarget(tools.GetLog(), target);
return ScrapeTargetHelper.FormatTarget(target);
}
}
public static class ScrapeTargetHelper
{
public static string FormatTarget(ILog log, IMetricsScrapeTarget target)
public static string FormatTarget(IMetricsScrapeTarget target)
{
var a = target.Container.GetAddress(log, target.MetricsPortTag);
var a = target.Container.GetAddress(target.MetricsPortTag);
var host = a.Host.Replace("http://", "").Replace("https://", "");
return $"{host}:{a.Port}";
}
+1 -1
View File
@@ -98,7 +98,7 @@ namespace ContinuousTests
{
cancelToken.ThrowIfCancellationRequested();
var address = n.Container.GetAddress(log, CodexContainerRecipe.ApiPortTag);
var address = n.Container.GetAddress(CodexContainerRecipe.ApiPortTag);
log.Log($"Checking {n.Container.Name} @ '{address}'...");
if (EnsureOnline(log, n))
@@ -2,6 +2,7 @@
using DistTestCore;
using GethPlugin;
using MetricsPlugin;
using BittorrentPlugin;
using NUnit.Framework;
using Utils;
@@ -66,5 +67,29 @@ namespace CodexTests.BasicTests
Assert.That(bootN, Is.EqualTo(followN));
Assert.That(discN, Is.LessThan(bootN));
}
[Test]
public void BittorrentPluginTest()
{
var tracker = Ci.StartBittorrentNode();
var msg = tracker.StartAsTracker();
msg = tracker.GetTrackerStats();
var seeder = Ci.StartBittorrentNode();
var torrent = seeder.CreateTorrent(10.MB(), tracker);
msg = seeder.AddTracker(tracker, torrent.LocalFilePath);
msg = seeder.StartDaemon();
Thread.Sleep(5000);
msg = tracker.GetTrackerStats();
var leecher = Ci.StartBittorrentNode();
var local = leecher.PutFile(torrent.TorrentBase64);
leecher.AddTracker(tracker, local);
msg = leecher.DownloadTorrent(local);
var yay = 0;
}
}
}
+1
View File
@@ -14,6 +14,7 @@
<ItemGroup>
<ProjectReference Include="..\..\Framework\DiscordRewards\DiscordRewards.csproj" />
<ProjectReference Include="..\..\ProjectPlugins\BittorrentPlugin\BittorrentPlugin.csproj" />
<ProjectReference Include="..\..\ProjectPlugins\CodexContractsPlugin\CodexContractsPlugin.csproj" />
<ProjectReference Include="..\..\ProjectPlugins\CodexDiscordBotPlugin\CodexDiscordBotPlugin.csproj" />
<ProjectReference Include="..\..\ProjectPlugins\CodexPlugin\CodexPlugin.csproj" />
+1 -1
View File
@@ -151,7 +151,7 @@ namespace AutoClient
{
try
{
var sp = await GetStoragePurchase(pid)!;
var sp = (await GetStoragePurchase(pid))!;
return sp.Request.Content.Cid;
}
catch (Exception ex)
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>4d58719c-20df-4407-bfb4-0f65a324a118</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Framework\FileUtils\FileUtils.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ActiveDebugProfile>Container (Dockerfile)</ActiveDebugProfile>
</PropertyGroup>
</Project>
@@ -0,0 +1,6 @@
@BittorrentDriver_HostAddress = http://localhost:5160
GET {{BittorrentDriver_HostAddress}}/weatherforecast/
Accept: application/json
###
@@ -0,0 +1,131 @@
using Logging;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
namespace BittorrentDriver.Controllers
{
[ApiController]
[Route("[controller]")]
public class TorrentController : ControllerBase
{
private readonly ILog log = new ConsoleLog();
private readonly TorrentTracker tracker = new TorrentTracker();
private readonly Transmission transmission;
public TorrentController()
{
transmission = new Transmission(log);
}
[HttpPut("starttracker")]
public string StartTracker([FromBody] int port)
{
return Try(() =>
{
Log("Starting tracker...");
return tracker.Start(port);
});
}
[HttpPost("addtracker")]
public string AddTracker([FromBody] AddTrackerInput input)
{
return Try(() =>
{
Log("Adding tracker: " + input.TrackerUrl + " - " + input.LocalFile);
return transmission.AddTracker(input.TrackerUrl, input.LocalFile);
});
}
[HttpGet("stats")]
public string GetTrackerStats()
{
return Try(() =>
{
return tracker.GetStats();
});
}
[HttpPost("postfile")]
public string PostFile([FromBody] PostFileInput input)
{
return Try(() =>
{
Log("Creating file..");
var file = transmission.PutLocalFile(input.Base64Content);
Log("File: " + file);
return file;
});
}
[HttpPut("daemon")]
public string StartDaemon([FromBody] int peerPort)
{
return Try(() =>
{
Log("Starting daemon...");
return transmission.StartDaemon(peerPort);
});
}
[HttpPost("create")]
public CreateTorrentResult CreateTorrent([FromBody] CreateTorrentInput input)
{
return Try(() =>
{
Log("Creating torrent file...");
return transmission.CreateNew(input.Size, input.TrackerUrl);
});
}
[HttpPost("download")]
public string DownloadTorrent([FromBody] DownloadTorrentInput input)
{
return Try(() =>
{
Log("Downloading torrent...");
return transmission.Download(input.LocalFile);
});
}
private T Try<T>(Func<T> value)
{
try
{
return value();
}
catch (Exception exc)
{
log.Error(exc.ToString());
throw;
}
}
private void Log(string v)
{
log.Log(v);
}
}
public class CreateTorrentInput
{
public int Size { get; set; }
public string TrackerUrl { get; set; } = string.Empty;
}
public class AddTrackerInput
{
public string TrackerUrl { get; set; } = string.Empty;
public string LocalFile { get; set; } = string.Empty;
}
public class DownloadTorrentInput
{
public string LocalFile { get; set; } = string.Empty;
}
public class PostFileInput
{
public string Base64Content { get; set; } = string.Empty;
}
}
+33
View File
@@ -0,0 +1,33 @@
# Variables
ARG IMAGE=ubuntu:24.10
ARG APP_HOME=/app
# Build
FROM ${IMAGE} AS builder
ARG APP_HOME
RUN apt-get update
RUN apt-get install dotnet-sdk-8.0 -y
WORKDIR ${APP_HOME}
COPY ./Tools/BittorrentDriver ./Tools/BittorrentDriver
COPY ./Framework ./Framework
RUN dotnet restore Tools/BittorrentDriver
RUN dotnet publish Tools/BittorrentDriver -c Release -o out
# Create
FROM ${IMAGE}
ARG DEBIAN_FRONTEND=noninteractive
ARG APP_HOME
ENV APP_HOME=${APP_HOME}
# Set up npm and bittorrent-tracker
RUN apt-get update
RUN apt-get install npm aspnetcore-runtime-8.0 -y
RUN npm install -g bittorrent-tracker
# Set up transmission
RUN apt-get install transmission-cli transmission-common transmission-daemon -y
WORKDIR ${APP_HOME}
COPY --from=builder ${APP_HOME}/out .
CMD dotnet ${APP_HOME}/BittorrentDriver.dll
+41
View File
@@ -0,0 +1,41 @@
namespace BittorrentDriver
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var listenPort = Environment.GetEnvironmentVariable("APIPORT");
if (string.IsNullOrEmpty(listenPort)) listenPort = "31100";
builder.WebHost.ConfigureKestrel((context, options) =>
{
options.ListenAnyIP(Convert.ToInt32(listenPort));
});
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
Console.WriteLine("TorrentController BittorrentDriver listening on port " + listenPort);
app.Run();
}
}
}
@@ -0,0 +1,52 @@
{
"profiles": {
"http": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5160"
},
"https": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7134;http://localhost:5160"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Container (Dockerfile)": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_HTTPS_PORTS": "8081",
"ASPNETCORE_HTTP_PORTS": "8080"
},
"publishAllPorts": true,
"useSSL": true
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:32045",
"sslPort": 44353
}
}
}
+4
View File
@@ -0,0 +1,4 @@
# Run from repo root folder:
docker build -t thatbenbierens/bittorrentdriver:init -f .\Tools\BittorrentDriver\Dockerfile .
docker push thatbenbierens/bittorrentdriver:init
+67
View File
@@ -0,0 +1,67 @@
using System.Diagnostics;
namespace BittorrentDriver
{
public class TorrentTracker
{
private Process? process;
private int? trackerPort;
public string Start(int port)
{
if (process != null) throw new Exception("Already started");
trackerPort = port;
var info = new ProcessStartInfo
{
FileName = "bittorrent-tracker",
Arguments =
$"--port {port} " +
$"--http " +
$"--stats " +
$"--interval=3000 " + // 3 seconds
$"&",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
};
process = Process.Start(info);
if (process == null) return "Failed to start";
process.OutputDataReceived += (sender, args) =>
{
Console.WriteLine("STDOUT: " + args.Data);
};
process.ErrorDataReceived += (sender, args) =>
{
Console.WriteLine("STDERR: " + args.Data);
};
process.BeginOutputReadLine();
process.BeginErrorReadLine();
Thread.Sleep(1000);
if (process.HasExited)
{
return
$"STDOUT: {process.StandardOutput.ReadToEnd()} " +
$"STDERR: {process.StandardError.ReadToEnd()}";
}
return "OK";
}
public string GetStats()
{
if (!trackerPort.HasValue) throw new Exception("Port value not set");
using var client = new HttpClient();
var task = client.GetAsync($"http://localhost:{trackerPort.Value}/stats");
task.Wait();
var strTask = task.Result.Content.ReadAsStringAsync();
strTask.Wait();
return strTask.Result;
}
}
}
+143
View File
@@ -0,0 +1,143 @@
using FileUtils;
using Logging;
using System.Buffers.Text;
using System.Diagnostics;
using System.Text;
using Utils;
namespace BittorrentDriver
{
public class Transmission
{
private readonly string dataDir;
private readonly ILog log;
public Transmission(ILog log)
{
dataDir = Path.Combine(Directory.GetCurrentDirectory(), "files");
Directory.CreateDirectory(dataDir);
this.log = log;
}
public CreateTorrentResult CreateNew(int size, string trackerUrl)
{
var file = CreateFile(size);
var outFile = Path.Combine(dataDir, Guid.NewGuid().ToString());
var base64 = CreateTorrentFile(file, outFile, trackerUrl);
return new CreateTorrentResult
{
LocalFilePath = outFile,
TorrentBase64 = base64
};
}
public string StartDaemon(int peerPort)
{
var info = new ProcessStartInfo
{
FileName = "transmission-daemon",
Arguments = $"--peerport={peerPort} " +
$"--download-dir={dataDir} " +
$"--watch-dir={dataDir} " +
$"--no-global-seedratio " +
$"--bind-address-ipv4=0.0.0.0 " +
$"--dht"
};
RunToComplete(info);
return "OK";
}
public string AddTracker(string trackerUrl, string localFile)
{
var info = new ProcessStartInfo
{
FileName = "transmission-edit",
Arguments = $"--add={trackerUrl} {localFile}"
};
RunToComplete(info);
return "OK";
}
public string PutLocalFile(string torrentBase64)
{
var torrentFile = Path.Combine(dataDir, Guid.NewGuid().ToString() + ".torrent");
File.WriteAllBytes(torrentFile, Convert.FromBase64String(torrentBase64));
return torrentFile;
}
public string Download(string localFile)
{
var peerPort = Environment.GetEnvironmentVariable("PEERPORT");
var info = new ProcessStartInfo
{
FileName = "transmission-cli",
Arguments =
$"--port={peerPort} " +
$"--download-dir={dataDir} " +
$"{localFile}"
};
RunToComplete(info);
return "OK";
}
private string CreateTorrentFile(TrackedFile file, string outFile, string trackerUrl)
{
try
{
var info = new ProcessStartInfo
{
FileName = "transmission-create",
Arguments = $"-o {outFile} -t {trackerUrl} {file.Filename}",
};
var process = RunToComplete(info);
log.Log(nameof(CreateTorrentFile) + " exited with: " + process.ExitCode);
if (!File.Exists(outFile)) throw new Exception("Outfile not created.");
return Convert.ToBase64String(File.ReadAllBytes(outFile));
}
catch (Exception ex)
{
log.Error("Failed to create torrent file: " + ex);
throw;
}
}
private Process RunToComplete(ProcessStartInfo info)
{
log.Log($"Running: {info.FileName} ({info.Arguments})");
var process = Process.Start(info);
if (process == null) throw new Exception("Failed to start");
process.WaitForExit(TimeSpan.FromMinutes(3));
return process;
}
private TrackedFile CreateFile(int size)
{
try
{
var fileManager = new FileManager(log, dataDir, numberSubfolders: false);
var file = fileManager.GenerateFile(size.Bytes());
log.Log("Generated file: " + file.Filename);
return file;
}
catch (Exception ex)
{
log.Error("Failed to create file: " + ex);
throw;
}
}
}
public class CreateTorrentResult
{
public string LocalFilePath { get; set; } = string.Empty;
public string TorrentBase64 { get; set; } = string.Empty;
}
}
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
+14
View File
@@ -76,6 +76,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TranscriptAnalysis", "Tools
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MarketInsights", "Tools\MarketInsights\MarketInsights.csproj", "{004614DF-1C65-45E3-882D-59AE44282573}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BittorrentPlugin", "ProjectPlugins\BittorrentPlugin\BittorrentPlugin.csproj", "{79866016-8CB3-4A30-9E5E-54070F27BE1E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BittorrentDriver", "Tools\BittorrentDriver\BittorrentDriver.csproj", "{AB9F7F80-9071-49A8-8B9D-D5B5D3E56560}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -202,6 +206,14 @@ Global
{004614DF-1C65-45E3-882D-59AE44282573}.Debug|Any CPU.Build.0 = Debug|Any CPU
{004614DF-1C65-45E3-882D-59AE44282573}.Release|Any CPU.ActiveCfg = Release|Any CPU
{004614DF-1C65-45E3-882D-59AE44282573}.Release|Any CPU.Build.0 = Release|Any CPU
{79866016-8CB3-4A30-9E5E-54070F27BE1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{79866016-8CB3-4A30-9E5E-54070F27BE1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{79866016-8CB3-4A30-9E5E-54070F27BE1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{79866016-8CB3-4A30-9E5E-54070F27BE1E}.Release|Any CPU.Build.0 = Release|Any CPU
{AB9F7F80-9071-49A8-8B9D-D5B5D3E56560}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB9F7F80-9071-49A8-8B9D-D5B5D3E56560}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB9F7F80-9071-49A8-8B9D-D5B5D3E56560}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB9F7F80-9071-49A8-8B9D-D5B5D3E56560}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -237,6 +249,8 @@ Global
{870DDFBE-D7ED-4196-9681-13CA947BDEA6} = {81AE04BC-CBFA-4E6F-B039-8208E9AFAAE7}
{C0EEBD32-23CB-45EC-A863-79FB948508C8} = {7591C5B3-D86E-4AE4-8ED2-B272D17FE7E3}
{004614DF-1C65-45E3-882D-59AE44282573} = {7591C5B3-D86E-4AE4-8ED2-B272D17FE7E3}
{79866016-8CB3-4A30-9E5E-54070F27BE1E} = {8F1F1C2A-E313-4E0C-BE40-58FB0BA91124}
{AB9F7F80-9071-49A8-8B9D-D5B5D3E56560} = {7591C5B3-D86E-4AE4-8ED2-B272D17FE7E3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {237BF0AA-9EC4-4659-AD9A-65DEB974250C}