aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile11
-rw-r--r--README.md17
-rw-r--r--global.ha2
-rw-r--r--main.ha7
-rw-r--r--req.ha44
-rw-r--r--templates/_footer.htmpl2
-rw-r--r--templates/index.htmpl8
-rw-r--r--url.ha6
9 files changed, 62 insertions, 38 deletions
diff --git a/.gitignore b/.gitignore
index f61aa76..c9ce4a7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/forge
-/templates.ha
+/.templates.ha
+/.version.ha
diff --git a/Makefile b/Makefile
index df09cae..a36e9de 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,10 @@
-forge: templates.ha *.ha
- hare build -o $@ .
+forge: .version.ha .templates.ha *.ha
+ hare build $(HAREFLAGS) -o $@ .
-templates.ha: templates/*.htmpl
+.templates.ha: templates/*.htmpl
htmplgen -o $@ $^
+
+.version.ha:
+ printf 'def VERSION="%s";\n' $(shell git describe --tags --always --dirty) > $@
+
+.PHONY: version.ha
diff --git a/README.md b/README.md
index 7b0adf8..42b2883 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,2 @@
-# Lindenii Forge
-
-**Work in progress.**
-
-This is the new implementation in the [Hare](https://harelang.org) programming
-language. We will set this as the primary branch once it reaches feature parity
-with the Go implementation.
-
-## Architecture
-
-* Most components are one single daemon written in Hare.
-* Because libssh is difficult to use and there aren't many other SSH server
- libraries for C or Hare, we will temporarily use
- [the gliberlabs SSH library for Go](https://github.com/gliderlabs/ssh)
- in a separate process, and communicate via UNIX domain sockets.
+**Please check out the `master` branch. Everything that used to be in the
+`hare` branch is now in `master`. The `hare` branch is deprectated.**
diff --git a/global.ha b/global.ha
index 11d7886..ac5ac14 100644
--- a/global.ha
+++ b/global.ha
@@ -5,7 +5,7 @@ let global: struct {
ssh_fp: str,
} = struct {
title: str = "Test Forge",
- version: str = "v0.0.0",
+ version: str = VERSION,
ssh_pubkey: str = "pubkey",
ssh_fp: str = "fp",
};
diff --git a/main.ha b/main.ha
index 0545e81..fc41240 100644
--- a/main.ha
+++ b/main.ha
@@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>
// Adapted from template by Willow Barraco <contact@willowbarraco.fr>
+use fs;
use getopt;
use log;
use net;
@@ -21,6 +22,8 @@ const usage: [_]getopt::help = [
('c', "config", "path to configuration file")
];
+let static_fs: nullable *fs::fs = null;
+
export fn main() void = {
const cmd = getopt::parse(os::args, usage...);
defer getopt::finish(&cmd);
@@ -31,10 +34,12 @@ export fn main() void = {
for (let opt .. cmd.opts) {
switch (opt.0) {
case 'c' => yield; // TODO: actually handle the config
- case => abort(); // unreachable
+ case => abort("unreachable");
};
};
+ static_fs = os::diropen("static")!;
+
const server = match (http::listen(ip_addr, port, net::tcp::reuseport, net::tcp::reuseaddr)) {
case let this: *http::server =>
yield this;
diff --git a/req.ha b/req.ha
index 2efa842..59f6438 100644
--- a/req.ha
+++ b/req.ha
@@ -2,15 +2,28 @@
// SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>
use fmt;
+use fs;
use htmpl;
use io;
+use mime;
use net::http;
use net::uri;
use strconv;
use strings;
-fn handlereq(conn: io::handle, request: *http::request) (void | io::error | nomem | uri::invalid) = {
- let segments = segments_from_path(request.target.raw_path)?;
+fn handlereq(conn: io::handle, request: *http::request) (void | io::error | nomem | fs::error) = {
+ let segments = match(segments_from_path(request.target.raw_path)) {
+ case let s: []str =>
+ yield s;
+ case uri::invalid =>
+ start_response(conn, 400, "text/plain")?;
+ fmt::fprintln(conn, "Invalid URI")?;
+ return void;
+ case nomem =>
+ return nomem;
+ case =>
+ abort("unreachable");
+ };
defer strings::freeall(segments);
let trailing_slash: bool = false;
@@ -23,7 +36,7 @@ fn handlereq(conn: io::handle, request: *http::request) (void | io::error | nome
if (len(segments) == 0) {
start_response(conn, 200, "text/html")?;
- return tp_index(conn, segments);
+ return tp_index(conn);
};
if (segments[0] == ":") {
@@ -40,6 +53,7 @@ fn handlereq(conn: io::handle, request: *http::request) (void | io::error | nome
fmt::fprintln(conn, "Error: Blank static endpoint")?;
return;
};
+
let fs_segments = segments[2 ..];
for (let fs_segment .. fs_segments) {
if (strings::contains(fs_segment, "/")) {
@@ -48,8 +62,28 @@ fn handlereq(conn: io::handle, request: *http::request) (void | io::error | nome
return;
};
};
- start_response(conn, 501, "text/plain")?;
- fmt::fprintln(conn, "Not implemented yet")?;
+ let fs_segment_path = strings::join("/", fs_segments...)?;
+ defer free(fs_segment_path);
+
+ let file = match (fs::open(static_fs as *fs::fs, fs_segment_path)) {
+ case let f: io::handle => yield f;
+ case fs::error =>
+ start_response(conn, 500, "text/plain")?;
+ fmt::fprintln(conn, "Filesystem error")?;
+ return;
+ };
+ defer io::close(file)!;
+
+ let ext = strings::rcut(fs_segments[len(fs_segments) - 1], ".").1;
+
+ let mimetype = match (mime::lookup_ext(ext)) {
+ case let m: *mime::mimetype => yield m.mime;
+ case null => yield "application/octet-stream";
+ };
+
+ start_response(conn, 200, mimetype)?;
+ io::copy(conn, file)?;
+
case =>
start_response(conn, 404, "text/plain")?;
fmt::fprintln(conn, "Error: Unknown system endpoint")?;
diff --git a/templates/_footer.htmpl b/templates/_footer.htmpl
index 71d5318..a0d1987 100644
--- a/templates/_footer.htmpl
+++ b/templates/_footer.htmpl
@@ -5,5 +5,5 @@
{{ " " }}
(<a href="/:/source/">source</a>,
{{ " " }}
-<a href="https://forge.lindenii.runxiyu.org/lindenii/forge/:/repos/server/">upstream</a>)
+<a href="https://forge.lindenii.runxiyu.org/lindenii/forge/:/repos/server/?branch=hare">upstream</a>)
{{ end }}
diff --git a/templates/index.htmpl b/templates/index.htmpl
index 1b4dd8b..e67cc09 100644
--- a/templates/index.htmpl
+++ b/templates/index.htmpl
@@ -1,4 +1,4 @@
-{{ define tp_index(handle: io::handle, segments: []str) (void | io::error | nomem) }}
+{{ define tp_index(handle: io::handle) (void | io::error | nomem) }}
<!DOCTYPE html>
<html lang="en">
<head>
@@ -7,12 +7,6 @@
</head>
<body>
{{ render _tp_header(handle, "test", "test") }}
-<h2>Path segments</h2>
-<ul>
- {{ for let s .. segments }}
- <li>{{ s }}</li>
- {{ end }}
-</ul>
<div class="padding-wrapper">
<table class="wide rounded">
<thead>
diff --git a/url.ha b/url.ha
index 6c4ef79..1c511ba 100644
--- a/url.ha
+++ b/url.ha
@@ -4,7 +4,7 @@
use strings;
use net::uri;
-// The result must be freed with strings::freeall.
+// The result, if not erroring out, must be freed with strings::freeall.
fn segments_from_path(s: str) ([]str | nomem | uri::invalid) = {
let sp: []str = strings::split(s, "/")?;
for (let i = 1z; i < len(sp); i += 1) {
@@ -12,9 +12,7 @@ fn segments_from_path(s: str) ([]str | nomem | uri::invalid) = {
case let s: str =>
sp[i - 1] = s;
case uri::invalid =>
- for (let j = 0z; j < i - 1; j += 1) {
- free(sp[j]);
- };
+ strings::freeall(sp[.. i - 1]);
return uri::invalid;
};
};