1- using Newtonsoft . Json . Linq ;
1+ using Newtonsoft . Json ;
2+ using Newtonsoft . Json . Linq ;
23using NLog ;
34using System ;
45using System . Collections . Generic ;
5- using System . IO ;
66using System . Linq ;
77using System . Net ;
88using System . Net . Http ;
@@ -14,14 +14,24 @@ public class Uploader : IUploader
1414 {
1515 private static readonly Logger _log = LogManager . GetCurrentClassLogger ( ) ;
1616#if DEBUG
17- private const string ApiEndpoint = "http ://hotsapi.local /api/v1" ;
17+ private const string ApiEndpoint = "https ://hotsapi.net /api/v1" ;
1818#else
19- const string ApiEndpoint = "https://hotsapi.net/api/v1" ;
19+ private const string ApiEndpoint = "https://hotsapi.net/api/v1" ;
2020#endif
2121
2222 private string UploadUrl => $ "{ ApiEndpoint } /upload?uploadToHotslogs={ UploadToHotslogs } ";
2323 private string BulkFingerprintUrl => $ "{ ApiEndpoint } /replays/fingerprints?uploadToHotslogs={ UploadToHotslogs } ";
2424 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+ }
2535
2636
2737 public bool UploadToHotslogs { get ; set ; }
@@ -41,62 +51,15 @@ public Uploader()
4151 public async Task Upload ( ReplayFile file , Task mayComplete )
4252 {
4353 var doDuplicateCheck = file . UploadStatus != UploadStatus . ReadyForUpload ;
44- file . UploadStatus = UploadStatus . Uploading ;
4554 if ( file . Fingerprint != null && doDuplicateCheck && await CheckDuplicate ( file . Fingerprint ) ) {
4655 _log . Debug ( $ "File { file } marked as duplicate") ;
4756 file . UploadStatus = UploadStatus . Duplicate ;
4857 } else {
58+ file . UploadStatus = UploadStatus . Uploading ;
4959 file . UploadStatus = await Upload ( file . Filename , mayComplete ) ;
5060 }
5161 }
5262
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-
10063 /// <summary>
10164 /// Upload replay
10265 /// </summary>
@@ -105,23 +68,29 @@ protected override bool TryComputeLength(out long length)
10568 public async Task < UploadStatus > Upload ( string file , Task mayComplete )
10669 {
10770 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+ }
11987 } else {
120- _log . Error ( $ "Unknown upload status '{ file } ': { json . status } ") ;
88+ _log . Warn ( $ "Error uploading file '{ file } ': { response } ") ;
12189 return UploadStatus . UploadError ;
12290 }
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 } ") ;
12594 return UploadStatus . UploadError ;
12695 }
12796 }
@@ -237,4 +206,5 @@ private static async Task<bool> CheckApiThrottling(WebResponse response)
237206 }
238207 }
239208 }
209+
240210}
0 commit comments