Skip to content

Commit 848e286

Browse files
committed
Work in progress
1 parent b9ee3a0 commit 848e286

21 files changed

+381
-317
lines changed

Assets/PatchKit Patcher/Scripts/AppData/Local/BaseWritableDirectory.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ public string Path
3131

3232
protected BaseWritableDirectory(string path)
3333
{
34-
Assert.IsFalse(UsedPaths.Contains(path),
35-
string.Format("You cannot create two instances of {0} pointing to the same path.", typeof(T)));
34+
// This makes no sense.
35+
//Assert.IsFalse(UsedPaths.Contains(path),
36+
// string.Format("You cannot create two instances of {0} pointing to the same path.", typeof(T)));
3637
Checks.ArgumentNotNullOrEmpty(path, "path");
3738

3839
DebugLogger.LogConstructor();

Assets/PatchKit Patcher/Scripts/AppData/Remote/Downloaders/ChunkedHttpDownloader.cs

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,29 @@ private struct DownloadJob
3535

3636
private readonly string _destinationFilePath;
3737

38-
private readonly RemoteResource _resource;
38+
private readonly ResourceUrl[] _urls;
39+
40+
private readonly ChunksData _chunksData;
41+
42+
private readonly long _size;
3943

4044
private bool _downloadHasBeenCalled;
4145

4246
public event DownloadProgressChangedHandler DownloadProgressChanged;
4347

44-
public ChunkedHttpDownloader([NotNull] string destinationFilePath, RemoteResource resource)
48+
public ChunkedHttpDownloader([NotNull] string destinationFilePath, [NotNull] ResourceUrl[] urls, ChunksData chunksData,
49+
long size)
4550
{
4651
if (string.IsNullOrEmpty(destinationFilePath))
4752
throw new ArgumentException("Value cannot be null or empty.", "destinationFilePath");
53+
if (urls == null) throw new ArgumentNullException("urls");
54+
if (size <= 0) throw new ArgumentOutOfRangeException("size");
4855

4956
_logger = PatcherLogManager.DefaultLogger;
5057
_destinationFilePath = destinationFilePath;
51-
_resource = resource;
58+
_urls = urls;
59+
_chunksData = chunksData;
60+
_size = size;
5261
}
5362

5463
private ChunkedFileStream OpenFileStream()
@@ -59,7 +68,7 @@ private ChunkedFileStream OpenFileStream()
5968
Directory.CreateDirectory(parentDirectory);
6069
}
6170

62-
return new ChunkedFileStream(_destinationFilePath, _resource.Size, _resource.ChunksData,
71+
return new ChunkedFileStream(_destinationFilePath, _size, _chunksData,
6372
HashFunction, ChunkedFileStream.WorkFlags.PreservePreviousFile);
6473
}
6574

@@ -68,17 +77,16 @@ public void Download(CancellationToken cancellationToken)
6877
try
6978
{
7079
_logger.LogDebug("Downloading...");
71-
_logger.LogTrace("resource.Size = " + _resource.Size);
72-
for (int i = 0; i < _resource.ResourceUrls.Length; i++)
80+
_logger.LogTrace("size = " + _size);
81+
for (int i = 0; i < _urls.Length; i++)
7382
{
74-
_logger.LogTrace("resource.ResourceUrls[" + i + "].Url = " + _resource.ResourceUrls[i].Url);
75-
_logger.LogTrace("resource.ResourceUrls[" + i + "].Country = " + _resource.ResourceUrls[i].Country);
76-
_logger.LogTrace(
77-
"resource.ResourceUrls[" + i + "].PartSize = " + _resource.ResourceUrls[i].PartSize);
83+
_logger.LogTrace("urls[" + i + "].Url = " + _urls[i].Url);
84+
_logger.LogTrace("urls[" + i + "].Country = " + _urls[i].Country);
85+
_logger.LogTrace("urls[" + i + "].PartSize = " + _urls[i].PartSize);
7886
}
7987

80-
_logger.LogTrace("resource.ChunksData.ChunkSize = " + _resource.ChunksData.ChunkSize);
81-
_logger.LogTrace("resource.ChunksData.Chunks.Length = " + _resource.ChunksData.Chunks.Length);
88+
_logger.LogTrace("chunksData.ChunkSize = " + _chunksData.ChunkSize);
89+
_logger.LogTrace("chunksData.Chunks.Length = " + _chunksData.Chunks.Length);
8290

8391
Assert.MethodCalledOnlyOnce(ref _downloadHasBeenCalled, "Download");
8492

@@ -89,7 +97,7 @@ public void Download(CancellationToken cancellationToken)
8997
do
9098
{
9199
bool success =
92-
_resource.ResourceUrls.Any(url => TryDownload(url, fileStream, cancellationToken));
100+
_urls.Any(url => TryDownload(url, fileStream, cancellationToken));
93101

94102
if (success)
95103
{
@@ -202,11 +210,10 @@ private bool TryDownload(ResourceUrl url, ChunkedFileStream fileStream, Cancella
202210

203211
private IEnumerable<DownloadJob> BuildDownloadJobQueue(ResourceUrl resourceUrl, long currentOffset)
204212
{
205-
long totalSize = _resource.Size;
206-
long partSize = resourceUrl.PartSize == 0 ? totalSize : resourceUrl.PartSize;
213+
long partSize = resourceUrl.PartSize == 0 ? _size : resourceUrl.PartSize;
207214

208-
int partCount = (int) (totalSize / partSize);
209-
partCount += totalSize % partSize != 0 ? 1 : 0;
215+
int partCount = (int) (_size / partSize);
216+
partCount += _size % partSize != 0 ? 1 : 0;
210217

211218
for (int i = 0; i < partCount; i++)
212219
{

Assets/PatchKit Patcher/Scripts/AppData/Remote/Downloaders/HttpDownloader.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,10 @@ public sealed class HttpDownloader : IHttpDownloader
3030

3131
public event DownloadProgressChangedHandler DownloadProgressChanged;
3232

33-
public HttpDownloader([NotNull] string destinationFilePath, [NotNull] string[] urls, long size)
33+
public HttpDownloader([NotNull] string destinationFilePath, [NotNull] string[] urls)
3434
{
3535
if (destinationFilePath == null) throw new ArgumentNullException("destinationFilePath");
3636
if (urls == null) throw new ArgumentNullException("urls");
37-
if (size <= 0) throw new ArgumentOutOfRangeException("size");
3837

3938
_logger = PatcherLogManager.DefaultLogger;
4039
_destinationFilePath = destinationFilePath;

Assets/PatchKit Patcher/Scripts/AppData/Remote/Downloaders/ITorrentDownloader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace PatchKit.Unity.Patcher.AppData.Remote.Downloaders
55
{
6-
public interface ITorrentDownloader : IDisposable
6+
public interface ITorrentDownloader
77
{
88
event DownloadProgressChangedHandler DownloadProgressChanged;
99

Assets/PatchKit Patcher/Scripts/AppData/Remote/Downloaders/TorrentClient.cs

Lines changed: 120 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
using System.Diagnostics;
33
using System.IO;
44
using System.Text;
5-
using Newtonsoft.Json.Linq;
5+
using JetBrains.Annotations;
6+
using Newtonsoft.Json;
7+
using PatchKit.Logging;
8+
using PatchKit.Unity.Patcher.AppData.Remote.Downloaders.Torrents;
9+
using PatchKit.Unity.Patcher.AppData.Remote.Downloaders.Torrents.Protocol;
10+
using PatchKit.Unity.Patcher.Cancellation;
611
using PatchKit.Unity.Patcher.Debug;
712

813
namespace PatchKit.Unity.Patcher.AppData.Remote.Downloaders
@@ -11,9 +16,9 @@ namespace PatchKit.Unity.Patcher.AppData.Remote.Downloaders
1116
/// Provides an easy access for torrent client program.
1217
/// </summary>
1318
/// <seealso cref="System.IDisposable" />
14-
public class TorrentClient : IDisposable
19+
public sealed class TorrentClient : IDisposable
1520
{
16-
private static readonly DebugLogger DebugLogger = new DebugLogger(typeof(TorrentClient));
21+
private readonly ILogger _logger;
1722

1823
private readonly ITorrentClientProcessStartInfoProvider _processStartInfoProvider;
1924

@@ -27,62 +32,110 @@ public class TorrentClient : IDisposable
2732

2833
public TorrentClient(ITorrentClientProcessStartInfoProvider processStartInfoProvider)
2934
{
30-
DebugLogger.LogConstructor();
31-
3235
_processStartInfoProvider = processStartInfoProvider;
3336

37+
_logger = PatcherLogManager.DefaultLogger;
3438
_process = StartProcess();
3539
_stdOutput = CreateStdOutputStream();
3640
_stdInput = CreateStdInputStream();
3741
}
3842

39-
/// <summary>
40-
/// Executes the command and returns the result.
41-
/// </summary>
42-
public JToken ExecuteCommand(string command)
43+
private static string ConvertPathForTorrentClient(string path)
44+
{
45+
return path.Replace("\\", "/").Replace(" ", "\\ ");
46+
}
47+
48+
public TorrentClientStatus GetStatus(CancellationToken cancellationToken)
4349
{
44-
Checks.ArgumentNotNull(command, "command");
50+
try
51+
{
52+
_logger.LogDebug("Getting status...");
53+
54+
var result = ExecuteCommand<TorrentClientStatus>("status", cancellationToken);
4555

46-
DebugLogger.Log(string.Format("Executing command {0}", command));
56+
_logger.LogDebug("Getting status finished.");
4757

48-
WriteCommand(command);
49-
string resultStr = ReadCommandResult();
50-
return ParseCommandResult(resultStr);
58+
return result;
59+
}
60+
catch (Exception e)
61+
{
62+
_logger.LogError("Getting status failed.", e);
63+
throw;
64+
}
5165
}
5266

53-
private void WriteCommand(string command)
67+
public void AddTorrent(string torrentFilePath, string downloadDirectoryPath,
68+
CancellationToken cancellationToken)
5469
{
55-
_stdInput.WriteLine(command);
56-
_stdInput.Flush();
70+
try
71+
{
72+
_logger.LogDebug(string.Format("Adding torrent from {0}...", torrentFilePath));
73+
_logger.LogTrace("downloadDirectoryPath = " + downloadDirectoryPath);
74+
75+
var convertedTorrentFilePath = ConvertPathForTorrentClient(torrentFilePath);
76+
var convertedDownloadDirectoryPath = ConvertPathForTorrentClient(downloadDirectoryPath);
77+
78+
_logger.LogTrace("convertedTorrentFilePath = " + convertedTorrentFilePath);
79+
_logger.LogTrace("convertedDownloadDirectoryPath = " + convertedDownloadDirectoryPath);
80+
81+
var command = string.Format("add-torrent {0} {1}", convertedTorrentFilePath,
82+
convertedDownloadDirectoryPath);
83+
84+
var result = ExecuteCommand<TorrentClientMessage>(command, cancellationToken);
85+
86+
_logger.LogTrace("result.Message = " + result.Message);
87+
_logger.LogTrace("result.Status = " + result.Status);
88+
89+
if (result.Status != "ok")
90+
{
91+
throw new AddTorrentFailureException(
92+
string.Format("Invalid add-torrent status: {0}", result.Status));
93+
}
94+
95+
_logger.LogDebug("Adding torrent finished.");
96+
}
97+
catch (Exception e)
98+
{
99+
_logger.LogError("Adding torrent failed.", e);
100+
throw;
101+
}
57102
}
58103

59-
private JToken ParseCommandResult(string resultStr)
104+
private TResult ExecuteCommand<TResult>([NotNull] string command, CancellationToken cancellationToken)
60105
{
61-
return JToken.Parse(resultStr);
106+
if (command == null) throw new ArgumentNullException("command");
107+
108+
_logger.LogDebug(string.Format("Executing command {0}", command));
109+
110+
_stdInput.WriteLine(command);
111+
_stdInput.Flush();
112+
113+
string resultStr = ReadCommandResult(cancellationToken);
114+
115+
_logger.LogDebug("Command execution finished. Parsing result...");
116+
_logger.LogTrace("result = " + resultStr);
117+
118+
var result = JsonConvert.DeserializeObject<TResult>(resultStr);
119+
120+
_logger.LogDebug("Parsing finished.");
121+
122+
return result;
62123
}
63124

64-
private string ReadCommandResult()
125+
private string ReadCommandResult(CancellationToken cancellationToken)
65126
{
66127
var str = new StringBuilder();
67128

68129
while (!str.ToString().EndsWith("#=end"))
69130
{
70-
ThrowIfProcessExited();
131+
cancellationToken.ThrowIfCancellationRequested();
71132

72-
str.Append((char)_stdOutput.Read());
133+
str.Append((char) _stdOutput.Read());
73134
}
74135

75136
return str.ToString().Substring(0, str.Length - 5);
76137
}
77138

78-
private void ThrowIfProcessExited()
79-
{
80-
if (_process.HasExited)
81-
{
82-
throw new TorrentClientException("torrent-client process has exited.");
83-
}
84-
}
85-
86139
private StreamReader CreateStdOutputStream()
87140
{
88141
return new StreamReader(_process.StandardOutput.BaseStream, CreateStdEncoding());
@@ -93,16 +146,22 @@ private StreamWriter CreateStdInputStream()
93146
return new StreamWriter(_process.StandardInput.BaseStream, CreateStdEncoding());
94147
}
95148

96-
private Encoding CreateStdEncoding()
149+
private static Encoding CreateStdEncoding()
97150
{
98151
return new UTF8Encoding(false);
99152
}
100153

101154
private Process StartProcess()
102155
{
103156
var processStartInfo = _processStartInfoProvider.GetProcessStartInfo();
157+
_logger.LogTrace("processStartInfo.FileName" + processStartInfo.FileName);
158+
_logger.LogTrace("processStartInfo.Arguments" + processStartInfo.Arguments);
159+
160+
_logger.LogDebug("Starting torrent-client process...");
161+
var process = Process.Start(processStartInfo);
162+
_logger.LogDebug("torrent-client process started.");
104163

105-
return Process.Start(processStartInfo);
164+
return process;
106165
}
107166

108167
public void Dispose()
@@ -116,38 +175,54 @@ public void Dispose()
116175
Dispose(false);
117176
}
118177

119-
protected virtual void Dispose(bool disposing)
178+
private void Dispose(bool disposing)
120179
{
121-
if(_disposed)
180+
if (_disposed)
122181
{
123182
return;
124183
}
125184

126-
DebugLogger.LogDispose();
127-
128-
if(disposing)
185+
if (disposing)
129186
{
130187
_stdOutput.Dispose();
131188
_stdInput.Dispose();
132189

133-
if (!_process.HasExited)
190+
try
134191
{
135-
try
192+
_logger.LogDebug("Killing torrent-client process...");
193+
194+
if (!_process.HasExited)
136195
{
137-
DebugLogger.Log("Killing torrent client process...");
196+
_logger.LogDebug("Sending kill request and waiting one second...");
138197
_process.Kill();
139198
_process.WaitForExit(1000);
140-
DebugLogger.Log("Torrent client process has been killed.");
199+
if (_process.HasExited)
200+
{
201+
_logger.LogDebug("torrent-client process killed.");
202+
}
203+
else
204+
{
205+
_logger.LogWarning(
206+
"torrent-client process hasn't been killed. Ignoring in order to not freeze application execution.");
207+
}
141208
}
142-
catch (Exception exception)
209+
else
143210
{
144-
DebugLogger.LogWarning("Killing torrent client process has failed: an exception has occured.");
145-
DebugLogger.LogException(exception);
211+
_logger.LogDebug("torrent-client process is already killed.");
146212
}
147213
}
214+
catch (Exception e)
215+
{
216+
_logger.LogError("Killing torrent-client process failed.", e);
217+
throw;
218+
}
219+
finally
220+
{
221+
_process.Dispose();
222+
}
148223
}
149224

150225
_disposed = true;
151226
}
152227
}
153-
}
228+
}

0 commit comments

Comments
 (0)