Skip to content

Commit 7c4d267

Browse files
committed
move image loading to Projection from MapTile
1 parent 2e0d351 commit 7c4d267

File tree

7 files changed

+149
-145
lines changed

7 files changed

+149
-145
lines changed

J4JMapLibrary/cache/FileSystemCache.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,16 +165,16 @@ public override void PurgeExpired()
165165
return false;
166166
}
167167

168-
var fileName =
169-
$"{mapTile.Region.Projection.Name}-{mapTile.QuadKey}{mapTile.Region.Projection.ImageFileExtension}";
170-
var filePath = Path.Combine( _cacheDir, fileName );
171-
172-
if( !await mapTile.LoadImageAsync( ctx ) )
168+
if( mapTile.ImageData == null )
173169
{
174-
Logger?.LogError("Failed to retrieve image data");
170+
Logger?.LogError("Map tile contains no image data");
175171
return false;
176172
}
177173

174+
var fileName =
175+
$"{mapTile.Region.Projection.Name}-{mapTile.QuadKey}{mapTile.Region.Projection.ImageFileExtension}";
176+
var filePath = Path.Combine( _cacheDir, fileName );
177+
178178
if( File.Exists( filePath ) )
179179
Logger?.LogWarning("Replacing map mapFragment with mapTile ID '{0}'", mapTile.FragmentId);
180180

J4JMapLibrary/cache/MemoryCache.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ protected override async Task<bool> LoadImageDataInternalAsync(
9999

100100
public override async Task<bool> AddEntryAsync( MapTile mapTile, CancellationToken ctx = default )
101101
{
102-
if( !await mapTile.LoadImageAsync( ctx ) )
102+
if( mapTile.ImageData == null )
103103
{
104-
Logger?.LogError("Failed to retrieve image data");
104+
Logger?.LogError("Map tile contains no image data");
105105
return false;
106106
}
107107

J4JMapLibrary/projections/base/IProjection.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,9 @@ Task<bool> LoadRegionAsync(
6565
MapRegion.MapRegion region,
6666
CancellationToken ctx = default
6767
);
68+
69+
byte[]? GetImage( MapTile mapTile );
70+
Task<byte[]?> GetImageAsync( MapTile mapTile, CancellationToken ctx = default );
71+
72+
Task<bool> LoadImageAsync( MapTile mapTile, CancellationToken ctx = default );
6873
}

J4JMapLibrary/projections/base/Projection.cs

Lines changed: 105 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
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;
1819
using System.Reflection;
1920
using J4JSoftware.J4JMapLibrary.MapRegion;
2021
using 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

J4JMapLibrary/projections/base/static-projection/StaticProjection.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public override async Task<MapTile> GetMapTileByProjectionCoordinatesAsync(
4040
)
4141
{
4242
var retVal = MapTile.CreateStaticMapTile( this, x, y, scale, LoggerFactory );
43-
await retVal.LoadImageAsync( ctx );
43+
await LoadImageAsync( retVal, ctx );
4444

4545
return retVal;
4646
}
@@ -59,7 +59,7 @@ protected override async Task<bool> LoadRegionInternalAsync(
5959
)
6060
{
6161
if( region.IsDefined )
62-
return await region.MapTiles[ 0, 0 ].LoadImageAsync( ctx );
62+
return await LoadImageAsync( region.MapTiles[ 0, 0 ], ctx );
6363

6464
Logger?.LogError( "Undefined static MapRegion" );
6565
return false;

J4JMapLibrary/projections/base/tiled-projection/TiledProjection.cs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public override async Task<MapTile> GetMapTileByProjectionCoordinatesAsync(
6767
var region = new MapRegion.MapRegion( this, LoggerFactory ) { Scale = scale };
6868

6969
var retVal = new MapTile( region, y ).SetXRelative( x );
70-
await retVal.LoadFromCacheAsync( TileCache, ctx );
70+
await LoadImageAsync( retVal, ctx );
7171

7272
return retVal;
7373
}
@@ -82,7 +82,7 @@ public override async Task<MapTile> GetMapTileByRegionCoordinatesAsync(
8282
var region = new MapRegion.MapRegion( this, LoggerFactory ) { Scale = scale };
8383

8484
var retVal = new MapTile( region, y ).SetXAbsolute( x );
85-
await retVal.LoadFromCacheAsync( TileCache, ctx );
85+
await LoadImageAsync(retVal, ctx);
8686

8787
return retVal;
8888
}
@@ -101,9 +101,34 @@ protected override async Task<bool> LoadRegionInternalAsync(
101101
{
102102
foreach( var mapTile in region )
103103
{
104-
await mapTile.LoadFromCacheAsync( TileCache, ctx );
104+
await LoadImageAsync( mapTile, ctx );
105105
}
106106

107107
return true;
108108
}
109+
110+
public override async Task<bool> LoadImageAsync(MapTile mapTile, CancellationToken ctx = default)
111+
{
112+
if (!mapTile.InProjection)
113+
{
114+
mapTile.ImageData = null;
115+
return true;
116+
}
117+
118+
var retVal = false;
119+
120+
if( TileCache != null )
121+
retVal = await TileCache.LoadImageAsync( mapTile, ctx );
122+
123+
if (retVal)
124+
return true;
125+
126+
mapTile.ImageData = await GetImageAsync( mapTile, ctx );
127+
retVal = mapTile.ImageData != null;
128+
129+
if( retVal && TileCache != null )
130+
await TileCache.AddEntryAsync( mapTile, ctx );
131+
132+
return retVal;
133+
}
109134
}

0 commit comments

Comments
 (0)