1515// You should have received a copy of the GNU General Public License along
1616// with ConsoleUtilities. If not, see <https://www.gnu.org/licenses/>.
1717
18+ using System . Net ;
1819using System . Reflection ;
1920using J4JSoftware . J4JMapLibrary . MapRegion ;
2021using Microsoft . Extensions . Logging ;
@@ -135,29 +136,12 @@ public abstract Task<MapTile> GetMapTileByRegionCoordinatesAsync(
135136 CancellationToken ctx = default
136137 ) ;
137138
138- public async Task < bool > LoadRegionAsync ( MapRegion . MapRegion region , CancellationToken ctx = default )
139- {
140- if ( ! Initialized )
141- {
142- Logger ? . LogError ( "Projection not initialized" ) ;
143- return false ;
144- }
145-
146- // only reload if we have to
147- var retVal = region . RegionChange != MapRegionChange . LoadRequired
148- || await LoadRegionInternalAsync ( region , ctx ) ;
149-
150- LoadComplete ? . Invoke ( this , retVal ) ;
151-
152- return retVal ;
153- }
154-
155139 bool IProjection . SetCredentials ( object credentials )
156140 {
157141 if ( credentials is TAuth castCredentials )
158142 return SetCredentials ( castCredentials ) ;
159143
160- Logger ? . LogError ( "Expected a {0} but received a {1}" , typeof ( TAuth ) , credentials . GetType ( ) ) ;
144+ Logger ? . LogError ( "Expected a {0} but received a {1}" , typeof ( TAuth ) , credentials . GetType ( ) ) ;
161145 return false ;
162146 }
163147
@@ -169,7 +153,7 @@ async Task<bool> IProjection.SetCredentialsAsync( object credentials, Cancellati
169153 return true ;
170154 }
171155
172- Logger ? . LogError ( "Expected a {0} but received a {1}" , typeof ( TAuth ) , credentials . GetType ( ) ) ;
156+ Logger ? . LogError ( "Expected a {0} but received a {1}" , typeof ( TAuth ) , credentials . GetType ( ) ) ;
173157 return false ;
174158 }
175159
@@ -198,15 +182,116 @@ public bool SetCredentials( TAuth credentials )
198182 if ( Credentials != null )
199183 return true ;
200184
201- Logger ? . LogError ( "Attempting to authenticate before setting credentials" ) ;
185+ Logger ? . LogError ( "Attempting to authenticate before setting credentials" ) ;
202186 return false ;
203187 }
204188
189+ public async Task < bool > LoadRegionAsync ( MapRegion . MapRegion region , CancellationToken ctx = default )
190+ {
191+ if ( ! Initialized )
192+ {
193+ Logger ? . LogError ( "Projection not initialized" ) ;
194+ return false ;
195+ }
196+
197+ // only reload if we have to
198+ var retVal = region . RegionChange != MapRegionChange . LoadRequired
199+ || await LoadRegionInternalAsync ( region , ctx ) ;
200+
201+ LoadComplete ? . Invoke ( this , retVal ) ;
202+
203+ return retVal ;
204+ }
205+
205206 protected abstract Task < bool > LoadRegionInternalAsync (
206207 MapRegion . MapRegion region ,
207208 CancellationToken ctx = default
208209 ) ;
209210
211+ public byte [ ] ? GetImage ( MapTile mapTile )
212+ {
213+ return Task . Run ( async ( ) => await GetImageAsync ( mapTile ) ) . Result ;
214+ }
215+
216+ public async Task < byte [ ] ? > GetImageAsync ( MapTile mapTile , CancellationToken ctx = default )
217+ {
218+ if ( ! mapTile . InProjection )
219+ return null ;
220+
221+ Logger ? . LogTrace ( "Beginning image retrieval from web" ) ;
222+
223+ var request = CreateMessage ( mapTile ) ;
224+ if ( request == null )
225+ {
226+ Logger ? . LogError ( "Could not create HttpRequestMessage for mapTile ({0})" , mapTile . FragmentId ) ;
227+ return null ;
228+ }
229+
230+ var uriText = request . RequestUri ! . AbsoluteUri ;
231+ var httpClient = new HttpClient ( ) ;
232+
233+ Logger ? . LogTrace ( "Querying {0}" , uriText ) ;
234+
235+ HttpResponseMessage ? response ;
236+
237+ try
238+ {
239+ response = MaxRequestLatency <= 0
240+ ? await httpClient . SendAsync ( request , ctx )
241+ : await httpClient . SendAsync ( request , ctx )
242+ . WaitAsync ( TimeSpan . FromMilliseconds ( MaxRequestLatency ) ,
243+ ctx ) ;
244+
245+ Logger ? . LogTrace ( "Got response from {0}" , uriText ) ;
246+ }
247+ catch ( Exception ex )
248+ {
249+ Logger ? . LogError ( "Image request from {0} failed, message was '{1}'" , request . RequestUri , ex . Message ) ;
250+ return null ;
251+ }
252+
253+ if ( response . StatusCode != HttpStatusCode . OK )
254+ {
255+ Logger ? . LogError ( "Image request from {0} failed with response code {1}, message was '{2}'" ,
256+ uriText ,
257+ response . StatusCode ,
258+ await response . Content . ReadAsStringAsync ( ctx ) ) ;
259+
260+ return null ;
261+ }
262+
263+ Logger ? . LogTrace ( "Reading response from {0}" , uriText ) ;
264+
265+ // extract image data from response
266+ try
267+ {
268+ await using var responseStream = MaxRequestLatency < 0
269+ ? await response . Content . ReadAsStreamAsync ( ctx )
270+ : await response . Content . ReadAsStreamAsync ( ctx )
271+ . WaitAsync ( TimeSpan . FromMilliseconds ( MaxRequestLatency ) ,
272+ ctx ) ;
273+
274+ var memStream = new MemoryStream ( ) ;
275+ await responseStream . CopyToAsync ( memStream , ctx ) ;
276+
277+ return memStream . ToArray ( ) ;
278+ }
279+ catch ( Exception ex )
280+ {
281+ Logger ? . LogError ( "Could not retrieve bitmap image stream from {0}, message was '{1}'" ,
282+ response . RequestMessage ! . RequestUri ! ,
283+ ex . Message ) ;
284+
285+ return null ;
286+ }
287+ }
288+
289+ public virtual async Task < bool > LoadImageAsync ( MapTile mapTile , CancellationToken ctx = default )
290+ {
291+ mapTile . ImageData = await GetImageAsync ( mapTile , ctx ) ;
292+ return mapTile . ImageData != null ;
293+ }
294+
210295 #region Scale
211296
212297 public int MinScale
0 commit comments