1
- using Newtonsoft . Json . Linq ;
1
+ using Newtonsoft . Json ;
2
+ using Newtonsoft . Json . Linq ;
2
3
using NLog ;
3
4
using System ;
4
5
using System . Collections . Generic ;
5
- using System . IO ;
6
6
using System . Linq ;
7
7
using System . Net ;
8
8
using System . Net . Http ;
@@ -14,14 +14,24 @@ public class Uploader : IUploader
14
14
{
15
15
private static readonly Logger _log = LogManager . GetCurrentClassLogger ( ) ;
16
16
#if DEBUG
17
- private const string ApiEndpoint = "http ://hotsapi.local /api/v1" ;
17
+ private const string ApiEndpoint = "https ://hotsapi.net /api/v1" ;
18
18
#else
19
- const string ApiEndpoint = "https://hotsapi.net/api/v1" ;
19
+ private const string ApiEndpoint = "https://hotsapi.net/api/v1" ;
20
20
#endif
21
21
22
22
private string UploadUrl => $ "{ ApiEndpoint } /upload?uploadToHotslogs={ UploadToHotslogs } ";
23
23
private string BulkFingerprintUrl => $ "{ ApiEndpoint } /replays/fingerprints?uploadToHotslogs={ UploadToHotslogs } ";
24
24
private string FingerprintOneUrl ( string fingerprint ) => $ "{ ApiEndpoint } /replays/fingerprints/v3/{ fingerprint } ?uploadToHotslogs={ UploadToHotslogs } ";
25
+ private HttpClient _httpClient ;
26
+ private HttpClient HttpClient
27
+ {
28
+ get {
29
+ if ( _httpClient == null ) {
30
+ _httpClient = new HttpClient ( ) ;
31
+ }
32
+ return _httpClient ;
33
+ }
34
+ }
25
35
26
36
27
37
public bool UploadToHotslogs { get ; set ; }
@@ -41,62 +51,15 @@ public Uploader()
41
51
public async Task Upload ( ReplayFile file , Task mayComplete )
42
52
{
43
53
var doDuplicateCheck = file . UploadStatus != UploadStatus . ReadyForUpload ;
44
- file . UploadStatus = UploadStatus . Uploading ;
45
54
if ( file . Fingerprint != null && doDuplicateCheck && await CheckDuplicate ( file . Fingerprint ) ) {
46
55
_log . Debug ( $ "File { file } marked as duplicate") ;
47
56
file . UploadStatus = UploadStatus . Duplicate ;
48
57
} else {
58
+ file . UploadStatus = UploadStatus . Uploading ;
49
59
file . UploadStatus = await Upload ( file . Filename , mayComplete ) ;
50
60
}
51
61
}
52
62
53
- private class ReplayUpload : HttpContent
54
- {
55
- private const int defaultBuffersize = 1024 ;
56
- private readonly string filename ;
57
- private readonly int buffersize ;
58
- private readonly Task mayComplete ;
59
-
60
- public ReplayUpload ( string filename , int buffersize , Task mayComplete )
61
- {
62
- this . filename = filename ;
63
- this . buffersize = buffersize ;
64
- this . mayComplete = mayComplete ;
65
- }
66
-
67
- public ReplayUpload ( string filename , int buffersize ) : this ( filename , buffersize , Task . CompletedTask ) { }
68
- public ReplayUpload ( string filename , Task canComplete ) : this ( filename , defaultBuffersize , canComplete ) { }
69
- public ReplayUpload ( string filename ) : this ( filename , defaultBuffersize , Task . CompletedTask ) { }
70
-
71
-
72
- protected override async Task SerializeToStreamAsync ( Stream stream , TransportContext context )
73
- {
74
- using ( var input = File . OpenRead ( filename ) ) {
75
- var buffer = new byte [ buffersize ] ;
76
- var i = 0 ;
77
- var done = false ;
78
- while ( ! done ) {
79
- var availableSpace = buffer . Length - i ;
80
- var bytesRead = await input . ReadAsync ( buffer , i , availableSpace ) ;
81
- if ( availableSpace > bytesRead ) {
82
- done = true ;
83
- await mayComplete ;
84
- }
85
- await stream . WriteAsync ( buffer , i , bytesRead ) ;
86
- i = 0 ;
87
- }
88
- await stream . FlushAsync ( ) ;
89
- stream . Close ( ) ;
90
- input . Close ( ) ;
91
- }
92
- }
93
- protected override bool TryComputeLength ( out long length )
94
- {
95
- length = - 1 ;
96
- return false ;
97
- }
98
- }
99
-
100
63
/// <summary>
101
64
/// Upload replay
102
65
/// </summary>
@@ -105,23 +68,29 @@ protected override bool TryComputeLength(out long length)
105
68
public async Task < UploadStatus > Upload ( string file , Task mayComplete )
106
69
{
107
70
try {
108
- string response ;
109
- using ( var client = new HttpClient ( ) ) {
110
- var upload = new ReplayUpload ( file , mayComplete ) ;
111
- var responseMessage = await client . PostAsync ( UploadUrl , upload ) ;
112
- response = await responseMessage . Content . ReadAsStringAsync ( ) ;
113
- }
114
- dynamic json = JObject . Parse ( response ) ;
115
- if ( ( bool ) json . success ) {
116
- if ( Enum . TryParse < UploadStatus > ( ( string ) json . status , out var status ) ) {
117
- _log . Debug ( $ "Uploaded file '{ file } ': { status } ") ;
118
- return status ;
71
+ var upload = new ReplayUpload ( file , mayComplete ) ;
72
+ var multipart = new MultipartFormDataContent {
73
+ { upload , "file" , file }
74
+ } ;
75
+ var responseMessage = await HttpClient . PostAsync ( UploadUrl , multipart ) ;
76
+ var response = await responseMessage . Content . ReadAsStringAsync ( ) ;
77
+ try {
78
+ dynamic json = JObject . Parse ( response ) ;
79
+ if ( ( bool ) json . success ) {
80
+ if ( Enum . TryParse < UploadStatus > ( ( string ) json . status , out var status ) ) {
81
+ _log . Debug ( $ "Uploaded file '{ file } ': { status } ") ;
82
+ return status ;
83
+ } else {
84
+ _log . Error ( $ "Unknown upload status '{ file } ': { json . status } ") ;
85
+ return UploadStatus . UploadError ;
86
+ }
119
87
} else {
120
- _log . Error ( $ "Unknown upload status '{ file } ': { json . status } ") ;
88
+ _log . Warn ( $ "Error uploading file '{ file } ': { response } ") ;
121
89
return UploadStatus . UploadError ;
122
90
}
123
- } else {
124
- _log . Warn ( $ "Error uploading file '{ file } ': { response } ") ;
91
+ }
92
+ catch ( JsonReaderException jre ) {
93
+ _log . Warn ( $ "Error processing upload response for file '{ file } ': { jre . Message } ") ;
125
94
return UploadStatus . UploadError ;
126
95
}
127
96
}
@@ -237,4 +206,5 @@ private static async Task<bool> CheckApiThrottling(WebResponse response)
237
206
}
238
207
}
239
208
}
209
+
240
210
}
0 commit comments