1
1
//! URI based system for retrieving assets
2
2
const std = @import ("std" );
3
3
const http = @import ("http.zig" );
4
+ const internal = @import ("internal.zig" );
5
+ const log = std .log .scoped (.assets );
4
6
const Uri = std .Uri ;
5
7
6
8
const GetError = Uri .ParseError || http .SendRequestError || error {UnsupportedScheme };
7
9
8
10
pub const AssetHandle = struct {
9
11
data : union (enum ) {
10
12
http : http.HttpResponse ,
13
+ file : std.fs.File ,
11
14
},
12
15
13
16
// TODO: intersection between file and http error
14
- pub const ReadError = http .HttpResponse .ReadError ;
17
+ pub const ReadError = http .HttpResponse .ReadError || std . fs . File . ReadError ;
15
18
pub const Reader = std .io .Reader (* AssetHandle , ReadError , read );
16
19
17
20
pub fn reader (self : * AssetHandle ) Reader {
18
21
return .{ .context = self };
19
22
}
20
23
24
+ pub fn bufferedReader (self : * AssetHandle ) std.io.BufferedReader (4096 , Reader ) {
25
+ return std .io .bufferedReaderSize (4096 , self .reader ());
26
+ }
27
+
21
28
pub fn read (self : * AssetHandle , dest : []u8 ) ReadError ! usize {
22
29
switch (self .data ) {
23
30
.http = > | * resp | {
24
31
return try resp .read (dest );
25
32
},
33
+ .file = > | file | {
34
+ return try file .read (dest );
35
+ },
26
36
}
27
37
}
28
38
@@ -31,23 +41,43 @@ pub const AssetHandle = struct {
31
41
.http = > | * resp | {
32
42
resp .deinit ();
33
43
},
44
+ .file = > | file | {
45
+ file .close ();
46
+ },
34
47
}
35
48
}
36
49
};
37
50
38
51
pub fn get (url : []const u8 ) GetError ! AssetHandle {
39
- const uri = try Uri .parse (url );
52
+ // Normalize the URI for the file:// scheme
53
+ var out_url : [4096 ]u8 = undefined ;
54
+ const new_size = std .mem .replacementSize (u8 , url , "file:///" , "file:/" );
55
+ _ = std .mem .replace (u8 , url , "file:///" , "file:/" , & out_url );
56
+
57
+ const uri = try Uri .parse (out_url [0.. new_size ]);
58
+ log .debug ("Loading {s}" , .{url });
59
+
60
+ if (std .mem .eql (u8 , uri .scheme , "asset" )) {
61
+ // TODO: on wasm load from the web (in relative path)
62
+ // TODO: on pc make assets into a bundle and use @embedFile ? this would ease loading times on windows which
63
+ // notoriously BAD I/O performance
64
+ var buffer : [std .fs .MAX_PATH_BYTES ]u8 = undefined ;
65
+ const cwd_path = try std .fs .realpath ("." , & buffer );
40
66
41
- if (std .mem .eql (u8 , uri .scheme , "assets" )) {
42
- @panic ("TODO: assets handler" );
67
+ const asset_path = try std .fs .path .join (internal .scratch_allocator , &.{ cwd_path , "assets/" , uri .path });
68
+ log .debug ("-> {s}" , .{asset_path });
69
+ const file = try std .fs .openFileAbsolute (asset_path , .{ .mode = .read_only });
70
+ return AssetHandle { .data = .{ .file = file } };
43
71
} else if (std .mem .eql (u8 , uri .scheme , "file" )) {
44
- @panic ("TODO: file handler" );
72
+ log .debug ("-> {s}" , .{uri .path });
73
+ const file = try std .fs .openFileAbsolute (uri .path , .{ .mode = .read_only });
74
+ return AssetHandle { .data = .{ .file = file } };
45
75
} else if (std .mem .eql (u8 , uri .scheme , "http" ) or std .mem .eql (u8 , uri .scheme , "https" )) {
46
76
const request = http .HttpRequest .get (url );
47
77
var response = try request .send ();
48
78
49
79
while (! response .isReady ()) {
50
- // TODO: suspend;
80
+ // TODO: suspend; when async is back
51
81
}
52
82
try response .checkError ();
53
83
0 commit comments