zig-webui icon indicating copy to clipboard operation
zig-webui copied to clipboard

feat: try to add embed folder

Open jinzhongjia opened this issue 1 year ago • 3 comments

jinzhongjia avatar Jul 13 '24 10:07 jinzhongjia

Try this Zig version of vfs.py, I did not test it yet.

  1. Run python vfs.py "myFolder" "vfs.zig"
  2. Import vfs.zig in main.zig of the serve_a_folder example
  3. Set vfs as file the handler MyWindow.setFileHandler(vfs);

vfs.py:

import os
import sys

def generate_vfs_zig(directory, output_file):
    files = []
    index_files = {}

    for root, _, filenames in os.walk(directory):
        for filename in filenames:
            filepath = os.path.join(root, filename)
            relative_path = os.path.relpath(filepath, directory)
            # Ensure path starts with a slash
            relative_path = '/' + relative_path.replace('\\', '/')
            files.append((relative_path, filepath))

            # Check for index files
            if filename.startswith("index."):
                dir_path = os.path.dirname(relative_path)
                if dir_path not in index_files:
                    index_files[dir_path] = relative_path

    with open(output_file, 'w') as zig_file:
        zig_file.write('const std = @import("std");\n')
        zig_file.write('const webui = @import("webui");\n\n')

        zig_file.write('pub const VirtualFile = struct {\n')
        zig_file.write('    path: []const u8,\n')
        zig_file.write('    data: []const u8,\n')
        zig_file.write('    length: usize,\n')
        zig_file.write('};\n\n')

        zig_file.write('pub const virtual_files = []const VirtualFile{\n')

        for relative_path, filepath in files:
            with open(filepath, 'rb') as f:
                data = f.read()
                zig_file.write('    VirtualFile{\n')
                zig_file.write(f'        .path = "{relative_path}",\n')
                zig_file.write('        .data = &[_]u8{')
                zig_file.write(','.join(f'0x{byte:02x}' for byte in data))
                zig_file.write('},\n')
                zig_file.write(f'        .length = {len(data)},\n')
                zig_file.write('    },\n')

        zig_file.write('};\n\n')

        zig_file.write('pub const virtual_files_count = @sizeOf(virtual_files) / @sizeOf(virtual_files[0]);\n\n')

        zig_file.write('pub const index_files = []const struct {\n')
        zig_file.write('    dir_path: []const u8,\n')
        zig_file.write('    index_path: []const u8,\n')
        zig_file.write('}{\n')
        for dir_path, index_path in index_files.items():
            zig_file.write(f'    .{{ "{dir_path}/", "{index_path}" }},\n')
        zig_file.write('};\n\n')

        zig_file.write('pub fn virtualFileSystem(path: []const u8) ?[]const u8 {\n')
        zig_file.write('    for (virtual_files) |file| {\n')
        zig_file.write('        if (std.mem.eql(u8, file.path, path)) {\n')
        zig_file.write('            return file.data;\n')
        zig_file.write('        }\n')
        zig_file.write('    }\n')
        zig_file.write('    return null;\n')
        zig_file.write('}\n\n')

        zig_file.write('pub fn vfs(path: []const u8) ?[]const u8 {\n')
        zig_file.write('    const file_data = virtualFileSystem(path);\n\n')

        zig_file.write('    if (file_data) |data| {\n')
        zig_file.write('        const content_type = webui.getMimeType(path);\n')
        zig_file.write('        const header = std.fmt.bufPrint(\n')
        zig_file.write('            "HTTP/1.1 200 OK\\r\\nContent-Type: {s}\\r\\nContent-Length: {d}\\r\\nCache-Control: no-cache\\r\\n\\r\\n",\n')
        zig_file.write('            .{content_type, data.len}\n')
        zig_file.write('        );\n')
        zig_file.write('        return header ++ data;\n')
        zig_file.write('    } else {\n')
        zig_file.write('        // Check for index file redirection\n')
        zig_file.write('        var redirect_path = std.mem.concat(u8, path, "/");\n')
        zig_file.write('        for (index_files) |entry| {\n')
        zig_file.write('            if (std.mem.eql(u8, entry.dir_path, redirect_path)) {\n')
        zig_file.write('                const header = std.fmt.bufPrint(\n')
        zig_file.write('                    "HTTP/1.1 302 Found\\r\\nLocation: {s}\\r\\nCache-Control: no-cache\\r\\n\\r\\n",\n')
        zig_file.write('                    .{entry.index_path}\n')
        zig_file.write('                );\n')
        zig_file.write('                return header;\n')
        zig_file.write('            }\n')
        zig_file.write('        }\n')
        zig_file.write('        return null;\n')
        zig_file.write('    }\n')
        zig_file.write('}\n')

if __name__ == '__main__':
    if len(sys.argv) != 3:
        print(f'Usage: {sys.argv[0]} <directory> <output_zig>')
        sys.exit(1)

    directory = sys.argv[1]
    output_zig = sys.argv[2]
    generate_vfs_zig(directory, output_zig)
    print(f'Generated {output_zig} from {directory}')

hassandraga avatar Jul 13 '24 16:07 hassandraga

A better solution can be achieved through zig theory, but there may not be time recently

jinzhongjia avatar Jul 14 '24 01:07 jinzhongjia

And I think this is not a priority to solve, because zig itself supports embedded files, but does not support embedded folders.

jinzhongjia avatar Jul 14 '24 01:07 jinzhongjia