| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- using Astralis;
- using Invercargill;
- using Invercargill.DataStructures;
- /**
- * FileServer Example
- *
- * A static file server that serves files from a directory specified
- * on the command line. Supports compression via gzip, brotli, and zstd.
- *
- * Usage: file-server <directory> [port]
- *
- * Examples:
- * file-server /var/www/html
- * file-server ./public 8080
- */
- // Root endpoint that shows server info
- class ServerInfoEndpoint : Object, Endpoint {
- private string served_directory;
- private int port;
-
- public ServerInfoEndpoint(string served_directory, int port) {
- this.served_directory = served_directory;
- this.port = port;
- }
-
- public string route { get { return "/__server_info"; } }
- public Method[] methods { owned get { return new Method[] { Method.GET }; } }
-
- public async HttpResult handle_request(HttpContext http_context, RouteInformation route) throws Error {
- var info = @"Astralis File Server
-
- Serving: $served_directory
- Port: $port
- Available compression: gzip, brotli, zstd
- Endpoints:
- /** - Serves files from the directory
- /__server_info - This information page
- Try:
- curl http://localhost:$port/
- curl --compressed http://localhost:$port/style.css
- ";
- return new HttpStringResult(info)
- .set_header("Content-Type", "text/plain");
- }
- }
- void main(string[] args) {
- // Parse command line arguments
- if (args.length < 2) {
- printerr("Usage: %s <directory> [port]\n", args[0]);
- printerr("\nServes files from the specified directory over HTTP.\n");
- printerr("Supports compression: gzip, brotli, zstd\n");
- printerr("\nExamples:\n");
- printerr(" %s /var/www/html\n", args[0]);
- printerr(" %s ./public 8080\n", args[0]);
- Process.exit(1);
- }
-
- string directory = args[1];
- int port = args.length > 2 ? int.parse(args[2]) : 8080;
-
- // Validate directory exists
- var dir_file = File.new_for_path(directory);
- if (!dir_file.query_exists()) {
- printerr("Error: Directory '%s' does not exist\n", directory);
- Process.exit(1);
- }
-
- // Check if it's actually a directory
- try {
- var info = dir_file.query_info("standard::type", FileQueryInfoFlags.NONE);
- if (info.get_file_type() != FileType.DIRECTORY) {
- printerr("Error: '%s' is not a directory\n", directory);
- Process.exit(1);
- }
- } catch (Error e) {
- printerr("Error checking directory: %s\n", e.message);
- Process.exit(1);
- }
-
- // Resolve to absolute path
- string absolute_path = dir_file.get_path();
-
- // Create the filesystem resource with deep matching
- FilesystemResource file_resource;
- try {
- file_resource = new FilesystemResource("/**", absolute_path);
- file_resource.allow_directory_listing = true;
- file_resource.index_file = "index.html";
- } catch (FilesystemResourceError e) {
- printerr("Error creating file resource: %s\n", e.message);
- Process.exit(1);
- }
-
- // Set up the router with file serving and server info endpoints
- var router = new EndpointRouter()
- .add_endpoint(new ServerInfoEndpoint(absolute_path, port))
- .add_endpoint(file_resource);
-
- // Create compression pipeline components
- // Order matters: we try brotli first (best compression), then zstd, then gzip (most compatible)
- var brotli = new BrotliCompressor();
- var zstd = new ZstdCompressor();
- var gzip = new GzipCompressor();
-
- // Build the pipeline with compression support
- var pipeline = new Pipeline()
- .add_component(gzip)
- .add_component(zstd)
- .add_component(brotli)
- .add_component(router);
-
- // Create and configure the server
- var server = new Server(port, pipeline);
-
- // Print startup information
- print("╔══════════════════════════════════════════════════════════════╗\n");
- print("║ Astralis File Server ║\n");
- print("╠══════════════════════════════════════════════════════════════╣\n");
- print(@"║ Serving: $(absolute_path)");
- if (absolute_path.length < 50) {
- for (int i = 0; i < 50 - absolute_path.length; i++) print(" ");
- }
- print(" ║\n");
- print(@"║ Port: $port");
- for (int i = 0; i < 50 - port.to_string().length; i++) print(" ");
- print(" ║\n");
- print("╠══════════════════════════════════════════════════════════════╣\n");
- print("║ Compression: gzip, brotli, zstd ║\n");
- print("╠══════════════════════════════════════════════════════════════╣\n");
- print("║ Try: ║\n");
- print(@"║ http://localhost:$port/");
- for (int i = 0; i < 50 - 21 - port.to_string().length; i++) print(" ");
- print(" ║\n");
- print(@"║ http://localhost:$port/__server_info");
- for (int i = 0; i < 50 - 35 - port.to_string().length; i++) print(" ");
- print(" ║\n");
- print("╚══════════════════════════════════════════════════════════════╝\n");
- print("\nPress Ctrl+C to stop the server\n\n");
-
- // Run the server
- server.run();
- }
|