~aw/patches

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
7 2

[PATCH mygit 0/3] colour scheme, caching, error pages

Johann Galle
Details
Message ID
<20210328161130.1161-1-johann@qwertqwefsday.eu>
DKIM signature
pass
Download raw message
This adds the colour scheme information for syntect and uses the Solarized
theme for the whole site. I confused this with some other patches, sorry again
for my strange message from earlier. I should definitely not use multiple PCs
at the same time.

The CSS file has been inflated because of all the CSS classes syntect uses. To
counteract this, I implemented caching for static files. A nice side effect of
this is that we now have a catchall error page.

[PATCH mygit 1/3] use Solarized colour scheme, dark mode

Johann Galle
Details
Message ID
<20210328161130.1161-2-johann@qwertqwefsday.eu>
In-Reply-To
<20210328161130.1161-1-johann@qwertqwefsday.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +138 -59
From: Johann150 <johann@qwertqwefsday.eu>

To be able to use dark mode in the form of CSS's prefers-color-scheme,
syntect had to be switched to output classes instead of hard coded colours.

This is a bit problematic as seen in the changes on the stylesheet. Some of
the CSS classes could probably be merged, but this is a nontrivial problem.

Because of the increased size, we should enable Caching for the stylesheet,
which tide's serve_file does not automatically do.
---
 src/main.rs                |  31 ++++---
 templates/static/style.css | 166 +++++++++++++++++++++++++++----------
 2 files changed, 138 insertions(+), 59 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index c5cb8cd..9964bfd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,7 +6,6 @@ use serde::Deserialize;
use std::fs;
use std::path::Path;
use std::str;
use syntect::highlighting::ThemeSet;
use syntect::parsing::SyntaxSet;
use tide::Request;

@@ -392,17 +391,16 @@ async fn repo_file(req: Request<()>) -> tide::Result {
    // TODO make sure I am escaping html properly here
    // TODO allow disabling of syntax highlighting
    // TODO -- dont pull in memory, use iterators if possible
    let syntax_set = SyntaxSet::load_defaults_nonewlines();
    let syntax_set = SyntaxSet::load_defaults_newlines();
    let extension = path
        .extension()
        .and_then(std::ffi::OsStr::to_str)
        .unwrap_or_default();
    let syntax_reference = syntax_set
    let syntax = syntax_set
        .find_syntax_by_extension(extension)
        .unwrap_or_else(|| syntax_set.find_syntax_plain_text());
    let ts = ThemeSet::load_defaults();
    let theme = &ts.themes["InspiredGitHub"]; // TODO make customizable
    let tmpl = match tree_entry.to_object(&repo)?.into_tree() {
	// this is a subtree
        Ok(tree) => RepoTreeTemplate {
            repo: &repo,
            tree,
@@ -410,21 +408,22 @@ async fn repo_file(req: Request<()>) -> tide::Result {
            spec: &spec,
        }
        .into(),
        // this is not a subtree, so it should be a blob i.e. file
        Err(tree_obj) => {
            use syntect::{html::{ClassedHTMLGenerator, ClassStyle}, util::LinesWithEndings};

            // get file contents from git object
            let file_string = str::from_utf8(tree_obj.as_blob().unwrap().content())?;
            let mut highlighter = syntect::easy::HighlightLines::new(&syntax_reference, &theme);
            let (mut output, bg) = syntect::html::start_highlighted_html_snippet(&theme);
            for (n, line) in syntect::util::LinesWithEndings::from(file_string).enumerate() {
                let regions = highlighter.highlight(line, &syntax_set);
            // create a highlighter that uses CSS classes so we can use prefers-color-scheme
            let mut highlighter = ClassedHTMLGenerator::new_with_class_style(&syntax, &syntax_set, ClassStyle::SpacedPrefixed{prefix:"code"});
            LinesWithEndings::from(file_string).for_each(|line| highlighter.parse_html_for_line_which_includes_newline(line));

            let mut output = String::from("<pre>\n");
            for (n, line) in highlighter.finalize().lines().enumerate() {
                output.push_str(&format!(
                    "<a href='#L{0}' id='L{0}' class='line'>{0}</a>",
                    n + 1
                    "<a href='#L{0}' id='L{0}' class='line'>{0}</a>{1}\n",
                    n + 1, line
                ));
                syntect::html::append_highlighted_html_for_styled_line(
                    &regions[..],
                    syntect::html::IncludeBackground::IfDifferent(bg),
                    &mut output,
                );
            }
            output.push_str("</pre>\n");

diff --git a/templates/static/style.css b/templates/static/style.css
index f65d706..61e9d25 100644
--- a/templates/static/style.css
+++ b/templates/static/style.css
@@ -1,10 +1,8 @@
body {
    padding: 0;
    border-top: 3px solid black;
    margin: 0;
    font-family: "Archivo", Helvetica, Arial, Sans-serif;
    word-wrap: break-word;
    background-color: white;
    line-height: 1.5;
}

@@ -12,10 +10,6 @@ body {
    max-width: 80ch;
}

a:visited {
    color: blue;
}

.repo-last-updated {
    font-style: italic;
}
@@ -36,7 +30,7 @@ a:visited {
    text-align: center;
    font-style: italic;
    font-size: .9rem;
    border-top: 1px solid black;
    border-top: 1px solid;
}

.line {
@@ -53,10 +47,6 @@ a:visited {
    user-select: none; /* Non-prefixed version, currently */
}

:target {
    background: #FFFACD;
}

.clone-url {
    font-family: "Roboto Mono", monospace;
    -webkit-user-select: all; /* Safari */
@@ -64,41 +54,30 @@ a:visited {
    text-align: right;
    padding-left: 2px;
    padding-right: 2px;
    display:inline-block
    display: inline-block
}

hr.thin {
    border: 0;
    height: 0;
    /* top border for light color scheme */
    border-top: 1px solid rgba(0, 0, 0, 0.1);
    /* bottom border for dark color scheme */
    border-bottom: 1px solid rgba(255, 255, 255, 0.3);
    border-top: 1px solid;
}

h1, h2, h3 {
     margin: 0px;
     margin: 0;
}

pre {
    line-height: 1.2;
    font-size: 1rem;
    overflow: auto;
    margin: 0px;
    padding: 0px;
}

tr:hover {
    background-color: #f0f0f0;
}

a:hover {
  text-decoration: none;
    margin: 0;
    padding: 0;
}

td {
    white-space: nowrap;
    margin: 0px;
    margin: 0;
    border-style:hidden;
    padding: 0;
}
@@ -112,20 +91,18 @@ table {
}

#navbar {
  /* background-color: #ededed; */
  padding-left: 2ch;
  padding-right: 2ch;
    padding-left: 2ch;
    padding-right: 2ch;
}

.links {
  background-color: #e8e8e8;
  display: block;
  padding-left: 2px;
    display: block;
    padding-left: 2px;
}

.main {
  padding-left: 2ch;
  padding-right: 2ch;
    padding-left: 2ch;
    padding-right: 2ch;
}


@@ -139,17 +116,120 @@ table {
    }
}

/* for code highlighting */

.markup.italic {
    font-style: italic;
}

.markup.bold {
    font-weight: bold;
}

/*
color scheme: Solarized
most of these classes are used by syntect

Light is the default color scheme, not using a media query for browser support.
*/
/* TODO simplify, e.g. merge CSS classes. */

.storage.modifier, .meta.scope.for-in-loop.shell, .variable.other.loop.shell, .meta.scope.case-block.shell, .meta.scope.case-body.shell {
    color: #586e75; /* Solarized base01 */
}

body, .code, .keyword.operator.comparison, .keyword.operator.assignment, .keyword.operator.arithmetic, .meta.brace.round, .meta.brace.curly, .punctuation.section, .punctuation.section.block, .punctuation.definition.parameters, .punctuation.section.group, .meta.selector.css, .text.html.basic, .meta.tag.other.html, .text.html.basic, .meta.tag.any.html, .text.html.basic, .meta.tag.block.any, .text.html.basic, .meta.tag.inline.any, .text.html.basic, .meta.tag.structure.any.html, .text.html.basic, .source.js.embedded.html, .punctuation.separator.key-value.html, .variable.other.readwrite.js, .variable.other.object.js, .variable.other.constant.js {
    color: #657b83; /* Solarized base00 */
}

hr.thin {
    border-top-color: #657b83; /* Solarized base00 */
}

.punctuation.definition.string {
    color: #839496; /* Solarized base0 */
}

.comment, .meta.documentation, .punctuation.definition.tag.html, .punctuation.definition.tag.begin, .punctuation.definition.tag.end, .meta.diff, .meta.diff.header, .constant.numeric.line-number.find-in-files {
    color: #93a1a1; /* Solarized base1 */
}

:target, tr:hover, .links, .meta.paragraph.markdown, .meta.dummy.line-break {
    background-color: #eee8d5; /* Solarized base2 */
}

body, .code {
    background-color: #fdf6e3; /* Solarized base3 */
}

.variable.function, .keyword.control.class, .entity.name, .entity.name.class, .entity.name.type.class, .entity.other.attribute-name, .entity.name.function, .constant, .constant.language, .meta.preprocessor, .support.constant.color, .invalid.deprecated.color.w3c-non-standard-color-name.scss, .entity.name.tag.css, .entity.name.tag.scss, .source.less, .keyword.control.html.elements, .source.sass, .keyword.control.untitled, .entity.other.attribute-name.class, .entity.other.attribute-name.id, .text.html.basic, .entity.other.attribute-name.html, .meta.tag.xml, .entity.other.attribute-name, .variable.other.constant.ruby, .meta.array, .support.function.construct.php, .meta.group.braces.tex, .string.other.math.tex, .string.other.math.tex, .support.type.exception.python, .markup.heading, .punctuation.definition.heading.markdown, .markup.changed.git_gutter {
    color: #b58900; /* Solarized yellow */
}

.meta.import, .keyword, .keyword.control.import, .keyword.control.import.from, .keyword.other.import, .keyword.control.at-rule.include, .keyword.control.at-rule.import, .entity.name.section, .constant.character, .constant.other, .support.type.exception, .keyword.other.special-method, .keyword.other.special-method.ruby, .entity.name.function.preprocessor.c, .meta.preprocessor.c.include, .meta.preprocessor.macro.c, .variable.parameter.function.latex, .support.function.section.latex {
    color: #cb4b16; /* Solarized orange */
}

.constant.character.escape, .support.function.construct, .keyword.other.new, .punctuation.separator.continuation, .other.package.exclude, .other.remove, .punctuation.section.group.tex, .punctuation.definition.arguments.begin.latex, .punctuation.definition.arguments.end.latex, .punctuation.definition.arguments.latex, .punctuation.definition.constant.math.tex, .punctuation.definition.string.begin.tex, .punctuation.definition.string.end.tex, .variable.parameter.definition.label.latex, .punctuation.definition.logical-expression.shell, .markup.deleted, .markup.deleted.git_gutter {
    color: #dc322f; /* Solarized red */
}

.variable.language {
    color: #d33682; /* Solarized magenta */
}

.constant.numeric, .constant.other.reference.link.markdown {
    color: #6c71c4; /* Solarized violet */
}

a, .variable, .entity.other.inherited-class, .entity.name.tag, .storage.type, .meta.brace.square, .punctuation.section.brackets, .entity.other.attribute-name.pseudo-element, .entity.other.attribute-name.tag.pseudo-element, .entity.other.attribute-name.pseudo-class, .entity.other.attribute-name.tag.pseudo-class, .support.function.perl, .meta.diff.range {
    color: #268bd2; /* Solarized blue */
}

.string, .string.regexp, .string.quoted.double, .string.quoted.single, .constant.other.symbol.ruby, .meta.preprocessor.c.include, .string.quoted.other.lt-gt.include.c, .meta.preprocessor.c.include, .punctuation.definition.string.begin.c, .meta.preprocessor.c.include, .punctuation.definition.string.end.c, .other.add, .text.tex.latex, .constant.other.math.tex, .constant.other.general.math.tex, .constant.other.general.math.tex, .constant.character.math.tex, .keyword.control.label.latex, .text.tex.latex, .constant.other.general.math.tex, .support.function.general.tex, .keyword.control.ref.latex, .markup.changed, .markup.underline.link.markdown, .meta.link.reference, .constant.other.reference.link.markdown, .entity.name.filename.find-in-files {
    color: #2aa198; /* Solarized cyan */
}

.keyword, .storage, .support, .support.type, .support.class, .punctuation.definition.variable, .support.function, .keyword.other.special-method.ruby, .support.function.be.latex, .storage.type.class.python, .storage.type.function.python, .storage.modifier.global.python, .storage.modifier.c++, .markup.inserted, .markup.quote, .markup.inserted.git_gutter {
    color: #859900; /* Solarized green */
}

.invalid {
    background-color: #ec9489;
}

/* Dark colour scheme for browsers that support it. */

@media (prefers-color-scheme: dark) {
    body {
        background: #212529;
        color: #f8f9fa;
    .storage.modifier, .meta.scope.for-in-loop.shell, .variable.other.loop.shell, .meta.scope.case-block.shell, .meta.scope.case-body.shell {
        color: #93a1a1; /* Solarized base1 */
    }

    body, .code, .keyword.operator.comparison, .keyword.operator.assignment, .keyword.operator.arithmetic, .meta.brace.round, .meta.brace.curly, .punctuation.section, .punctuation.section.block, .punctuation.definition.parameters, .punctuation.section.group, .meta.selector.css, .text.html.basic, .meta.tag.other.html, .text.html.basic, .meta.tag.any.html, .text.html.basic, .meta.tag.block.any, .text.html.basic, .meta.tag.inline.any, .text.html.basic, .meta.tag.structure.any.html, .text.html.basic, .source.js.embedded.html, .punctuation.separator.key-value.html, .variable.other.readwrite.js, .variable.other.object.js, .variable.other.constant.js {
        color: #839496; /* Solarized base0 */
    }

    hr.thin {
        border-top-color: #839496; /* Solarized base0 */
    }

    .punctuation.definition.string {
        color: #657b83; /* Solarized base00 */
    }

    .comment, .meta.documentation, .punctuation.definition.tag.html, .punctuation.definition.tag.begin, .punctuation.definition.tag.end, .meta.diff, .meta.diff.header, .constant.numeric.line-number.find-in-files {
        color: #586e75; /* Solarized base01 */
    }

    :target, tr:hover, .links, .meta.paragraph.markdown, .meta.dummy.line-break {
        background-color: #073642; /* Solarized base02 */
    }

    :target {
        background: #ffffff;
    body, .code {
        background-color: #002b36; /* Solarized base03 */
    }

    tr:hover {
        background-color: #0f0f0f;
    .invalid {
        background-color: #6e2e32;
    }
}
-- 
2.20.1

[PATCH mygit 2/3] format, add catchall error pages

Johann Galle
Details
Message ID
<20210328161130.1161-3-johann@qwertqwefsday.eu>
In-Reply-To
<20210328161130.1161-1-johann@qwertqwefsday.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +29 -8
From: Johann150 <johann@qwertqwefsday.eu>

---
 src/errorpage.rs |  8 ++++++++
 src/main.rs      | 29 +++++++++++++++++++++--------
 2 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/src/errorpage.rs b/src/errorpage.rs
index 3df280f..a1436d3 100644
--- a/src/errorpage.rs
+++ b/src/errorpage.rs
@@ -24,6 +24,14 @@ impl<State: Clone + Send + Sync + 'static> Middleware<State> for ErrorToErrorpag
                message: err.into_inner().to_string(),
            }
            .into();
            if status == 405 {
                // The origin server MUST generate an Allow header field in
                // a 405 response containing a list of the target
                // resource's currently supported methods. - RFC 7231§6.5.5
                //
                // We only ever support GET requests.
                response.insert_header("Allow", "GET");
            }
            response.set_status(status);
        }

diff --git a/src/main.rs b/src/main.rs
index 9964bfd..2ba9f68 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,7 +7,7 @@ use std::fs;
use std::path::Path;
use std::str;
use syntect::parsing::SyntaxSet;
use tide::Request;
use tide::{Request, Response};

mod errorpage;

@@ -400,7 +400,7 @@ async fn repo_file(req: Request<()>) -> tide::Result {
        .find_syntax_by_extension(extension)
        .unwrap_or_else(|| syntax_set.find_syntax_plain_text());
    let tmpl = match tree_entry.to_object(&repo)?.into_tree() {
	// this is a subtree
        // this is a subtree
        Ok(tree) => RepoTreeTemplate {
            repo: &repo,
            tree,
@@ -410,19 +410,28 @@ async fn repo_file(req: Request<()>) -> tide::Result {
        .into(),
        // this is not a subtree, so it should be a blob i.e. file
        Err(tree_obj) => {
            use syntect::{html::{ClassedHTMLGenerator, ClassStyle}, util::LinesWithEndings};
            use syntect::{
                html::{ClassStyle, ClassedHTMLGenerator},
                util::LinesWithEndings,
            };

            // get file contents from git object
            let file_string = str::from_utf8(tree_obj.as_blob().unwrap().content())?;
            // create a highlighter that uses CSS classes so we can use prefers-color-scheme
            let mut highlighter = ClassedHTMLGenerator::new_with_class_style(&syntax, &syntax_set, ClassStyle::SpacedPrefixed{prefix:"code"});
            LinesWithEndings::from(file_string).for_each(|line| highlighter.parse_html_for_line_which_includes_newline(line));
            let mut highlighter = ClassedHTMLGenerator::new_with_class_style(
                &syntax,
                &syntax_set,
                ClassStyle::SpacedPrefixed { prefix: "code" },
            );
            LinesWithEndings::from(file_string)
                .for_each(|line| highlighter.parse_html_for_line_which_includes_newline(line));

            let mut output = String::from("<pre>\n");
            for (n, line) in highlighter.finalize().lines().enumerate() {
                output.push_str(&format!(
                    "<a href='#L{0}' id='L{0}' class='line'>{0}</a>{1}\n",
                    n + 1, line
                    n + 1,
                    line
                ));
            }
            output.push_str("</pre>\n");
@@ -551,10 +560,12 @@ async fn main() -> Result<(), std::io::Error> {
        .serve_file("templates/static/style.css")?; // TODO configurable
    app.at("/:repo_name").get(repo_home);
    app.at("/:repo_name/").get(repo_home);
    // git clone stuff -- handle thse urls

    // git clone stuff
    app.at("/:repo_name/info/refs").get(git_data);
    app.at("/:repo_name/HEAD").get(git_data);
    app.at("/:repo_name/objects/*obj").get(git_data);

    app.at("/:repo_name/commit/:commit").get(repo_commit);
    app.at("/:repo_name/refs").get(repo_refs);
    app.at("/:repo_name/log").get(repo_log);
@@ -563,8 +574,10 @@ async fn main() -> Result<(), std::io::Error> {
    app.at("/:repo_name/tree/:ref").get(repo_tree);
    app.at("/:repo_name/tree/:ref/item/*object_name")
        .get(repo_file);
    app.at("*")
        .get(|_| async { Result::<Response, tide::Error>::Err(tide::Error::from_str(404, "This page does not exist.")) })
        .all(|_| async { Result::<Response, tide::Error>::Err(tide::Error::from_str(405, "This method is not allowed.")) });
    // Raw files, patch files
    app.listen(format!("[::]:{}", CONFIG.port)).await?;
    // app.all 404
    Ok(())
}
-- 
2.20.1

[PATCH mygit 3/3] caching for static resources

Johann Galle
Details
Message ID
<20210328161130.1161-4-johann@qwertqwefsday.eu>
In-Reply-To
<20210328161130.1161-1-johann@qwertqwefsday.eu> (view parent)
DKIM signature
pass
Download raw message
Patch: +112 -23
From: Johann150 <johann@qwertqwefsday.eu>

---
 src/errorpage.rs |  29 +++++++++----
 src/main.rs      | 106 ++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 112 insertions(+), 23 deletions(-)

diff --git a/src/errorpage.rs b/src/errorpage.rs
index a1436d3..f6995f6 100644
--- a/src/errorpage.rs
+++ b/src/errorpage.rs
@@ -15,24 +15,35 @@ pub struct ErrorToErrorpage;
impl<State: Clone + Send + Sync + 'static> Middleware<State> for ErrorToErrorpage {
    async fn handle(&self, req: Request<State>, next: Next<'_, State>) -> tide::Result {
        let resource = req.url().path().to_string();
        let method = req.method();
        let mut response = next.run(req).await;
        if let Some(err) = response.take_error() {
            let status = err.status();
            response = ErrorTemplate {
                resource,
                status,
                message: err.into_inner().to_string(),

            if method == tide::http::Method::Head {
                // the server MUST NOT send a message body in the response
                // - RFC 7231 § 4.3.2
                response.take_body();
            } else {
                response = ErrorTemplate {
                    resource,
                    status,
                    message: err.into_inner().to_string(),
                }
                .into();
                response.set_status(status);
            }
            .into();

            if status == 405 {
                // The origin server MUST generate an Allow header field in
                // a 405 response containing a list of the target
                // resource's currently supported methods. - RFC 7231§6.5.5
                // resource's currently supported methods.
                // - RFC 7231 § 6.5.5
                //
                // We only ever support GET requests.
                response.insert_header("Allow", "GET");
                // We only ever support GET or HEAD requests.
                // tide adds support for HEAD automatically if we implement GET
                response.insert_header("Allow", "GET, HEAD");
            }
            response.set_status(status);
        }

        Ok(response)
diff --git a/src/main.rs b/src/main.rs
index 2ba9f68..5bee9fb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,7 +3,8 @@ use askama::Template;
use git2::{Commit, Diff, DiffDelta, Reference, Repository, Tree, TreeEntry};
use once_cell::sync::Lazy;
use serde::Deserialize;
use std::fs;
use std::fs::{self, File};
use std::io::Read;
use std::path::Path;
use std::str;
use syntect::parsing::SyntaxSet;
@@ -468,10 +469,7 @@ async fn git_data(req: Request<()>) -> tide::Result {
            } else if !path.is_file() {
                // Either the requested resource does not exist or it is not
                // a file, i.e. a directory.
                Err(tide::Error::from_str(
                    404,
                    "The file you tried to access does not exist.",
                ))
                Err(tide::Error::from_str(404, "This page does not exist."))
            } else {
                // ok - inside the repo directory
                let mut resp = tide::Response::new(200);
@@ -488,6 +486,89 @@ async fn git_data(req: Request<()>) -> tide::Result {
    }
}

/// Serve a file from ./templates/static/
async fn static_resource(req: Request<()>) -> tide::Result {
    use tide::http::conditional::{IfModifiedSince, LastModified};

    // only use a File handle here because we might not need to load the file
    let file_mime_option = match req.url().path() {
        "/style.css" => Some((
            File::open("templates/static/style.css").unwrap(),
            tide::http::mime::CSS,
        )),
        "/robots.txt" => Some((
            File::open("templates/static/robots.txt").unwrap(),
            tide::http::mime::PLAIN,
        )),
        _ => None,
    };

    match file_mime_option {
        Some((mut file, mime)) => {
            let metadata = file.metadata().unwrap();
            let last_modified = metadata.modified().unwrap();

            let header = IfModifiedSince::from_headers(&req).unwrap();

            // check cache validating headers
            if matches!(header, Some(date) if IfModifiedSince::new(last_modified) <= date) {
                // the file has not changed
                let mut response = Response::new(304);
                response.set_content_type(mime);
                LastModified::new(last_modified).apply(&mut response);

                /*
                A server MAY send a Content-Length header field in a 304
                response to a conditional GET request; a server MUST NOT send
                Content-Length in such a response unless its field-value equals
                the decimal number of octets that would have been sent in the
                payload body of a 200 response to the same request.
                - RFC 7230 § 3.3.2
                */
                response.insert_header("Content-Length", metadata.len().to_string());

                return Ok(response);
            }

            let mut response = Response::new(200);

            match req.method() {
                tide::http::Method::Head => {
                    /*
                    A server MAY send a Content-Length header field in a
                    response to a HEAD request; a server MUST NOT send
                    Content-Length in such a response unless its field-value
                    equals the decimal number of octets that would have been
                    sent in the payload body of a response if the same request
                    had used the GET method.
                    - RFC 7230 § 3.3.2
                    */
                    response.insert_header(
                        "Content-Length",
                        file.metadata().unwrap().len().to_string(),
                    );
                }
                tide::http::Method::Get => {
                    // load the file from disk
                    let mut content = String::new();
                    file.read_to_string(&mut content).unwrap();
                    response.set_body(content);
                }
                _ => return Err(tide::Error::from_str(405, "")),
            }

            response.set_content_type(mime);
            LastModified::new(last_modified).apply(&mut response);
            Ok(response)
        }
        None if req.method() == tide::http::Method::Get => {
            Err(tide::Error::from_str(404, "This page does not exist."))
        }
        // issue a 405 error since this is used as the catchall
        None => Err(tide::Error::from_str(405, "")),
    }
}

mod filters {
    use super::*;

@@ -554,10 +635,7 @@ async fn main() -> Result<(), std::io::Error> {
    let mut app = tide::new();
    app.with(errorpage::ErrorToErrorpage);
    app.at("/").get(index);
    app.at("/robots.txt")
        .serve_file("templates/static/robots.txt")?; // TODO configurable
    app.at("/style.css")
        .serve_file("templates/static/style.css")?; // TODO configurable

    app.at("/:repo_name").get(repo_home);
    app.at("/:repo_name/").get(repo_home);

@@ -566,17 +644,17 @@ async fn main() -> Result<(), std::io::Error> {
    app.at("/:repo_name/HEAD").get(git_data);
    app.at("/:repo_name/objects/*obj").get(git_data);

    // web pages
    app.at("/:repo_name/commit/:commit").get(repo_commit);
    app.at("/:repo_name/refs").get(repo_refs);
    app.at("/:repo_name/log").get(repo_log);
    app.at("/:repo_name/log/:ref").get(repo_log); // ref optional
    app.at("/:repo_name/log/:ref").get(repo_log); // ref is optional
    app.at("/:repo_name/tree").get(repo_tree);
    app.at("/:repo_name/tree/:ref").get(repo_tree);
    app.at("/:repo_name/tree/:ref").get(repo_tree); // ref is optional
    app.at("/:repo_name/tree/:ref/item/*object_name")
        .get(repo_file);
    app.at("*")
        .get(|_| async { Result::<Response, tide::Error>::Err(tide::Error::from_str(404, "This page does not exist.")) })
        .all(|_| async { Result::<Response, tide::Error>::Err(tide::Error::from_str(405, "This method is not allowed.")) });

    app.at("*").all(static_resource);
    // Raw files, patch files
    app.listen(format!("[::]:{}", CONFIG.port)).await?;
    Ok(())
-- 
2.20.1

Re: [PATCH mygit 1/3] use Solarized colour scheme, dark mode

Details
Message ID
<CA94FQ0M78CU.30D5XKO9UTQIR@debian-alex>
In-Reply-To
<20210328161130.1161-2-johann@qwertqwefsday.eu> (view parent)
DKIM signature
fail
Download raw message
DKIM signature: fail
Hi Johann -- it looks like this doesn't merge with the main remote
branch -- I had forgotten to push a commit that I had locally where I
reverted some of the style.css changes I had made earlier. I can either
do the merge commit myself or you can submit a new patch -- I'm not sure
which is better?

Alex

On Sun Mar 28, 2021 at 9:11 AM PDT, Johann Galle wrote:
> From: Johann150 <johann@qwertqwefsday.eu>
>
> To be able to use dark mode in the form of CSS's prefers-color-scheme,
> syntect had to be switched to output classes instead of hard coded
> colours.
>
> This is a bit problematic as seen in the changes on the stylesheet. Some
> of
> the CSS classes could probably be merged, but this is a nontrivial
> problem.
>
> Because of the increased size, we should enable Caching for the
> stylesheet,
> which tide's serve_file does not automatically do.
> ---
> src/main.rs | 31 ++++---
> templates/static/style.css | 166 +++++++++++++++++++++++++++----------
> 2 files changed, 138 insertions(+), 59 deletions(-)
>
> diff --git a/src/main.rs b/src/main.rs
> index c5cb8cd..9964bfd 100644
> --- a/src/main.rs
> +++ b/src/main.rs
> @@ -6,7 +6,6 @@ use serde::Deserialize;
> use std::fs;
> use std::path::Path;
> use std::str;
> -use syntect::highlighting::ThemeSet;
> use syntect::parsing::SyntaxSet;
> use tide::Request;
>  
> @@ -392,17 +391,16 @@ async fn repo_file(req: Request<()>) ->
> tide::Result {
> // TODO make sure I am escaping html properly here
> // TODO allow disabling of syntax highlighting
> // TODO -- dont pull in memory, use iterators if possible
> - let syntax_set = SyntaxSet::load_defaults_nonewlines();
> + let syntax_set = SyntaxSet::load_defaults_newlines();
> let extension = path
> .extension()
> .and_then(std::ffi::OsStr::to_str)
> .unwrap_or_default();
> - let syntax_reference = syntax_set
> + let syntax = syntax_set
> .find_syntax_by_extension(extension)
> .unwrap_or_else(|| syntax_set.find_syntax_plain_text());
> - let ts = ThemeSet::load_defaults();
> - let theme = &ts.themes["InspiredGitHub"]; // TODO make customizable
> let tmpl = match tree_entry.to_object(&repo)?.into_tree() {
> + // this is a subtree
> Ok(tree) => RepoTreeTemplate {
> repo: &repo,
> tree,
> @@ -410,21 +408,22 @@ async fn repo_file(req: Request<()>) ->
> tide::Result {
> spec: &spec,
> }
> .into(),
> + // this is not a subtree, so it should be a blob i.e. file
> Err(tree_obj) => {
> + use syntect::{html::{ClassedHTMLGenerator, ClassStyle},
> util::LinesWithEndings};
> +
> + // get file contents from git object
> let file_string =
> str::from_utf8(tree_obj.as_blob().unwrap().content())?;
> - let mut highlighter =
> syntect::easy::HighlightLines::new(&syntax_reference, &theme);
> - let (mut output, bg) =
> syntect::html::start_highlighted_html_snippet(&theme);
> - for (n, line) in
> syntect::util::LinesWithEndings::from(file_string).enumerate() {
> - let regions = highlighter.highlight(line, &syntax_set);
> + // create a highlighter that uses CSS classes so we can use
> prefers-color-scheme
> + let mut highlighter =
> ClassedHTMLGenerator::new_with_class_style(&syntax, &syntax_set,
> ClassStyle::SpacedPrefixed{prefix:"code"});
> + LinesWithEndings::from(file_string).for_each(|line|
> highlighter.parse_html_for_line_which_includes_newline(line));
> +
> + let mut output = String::from("<pre>\n");
> + for (n, line) in highlighter.finalize().lines().enumerate() {
> output.push_str(&format!(
> - "<a href='#L{0}' id='L{0}' class='line'>{0}</a>",
> - n + 1
> + "<a href='#L{0}' id='L{0}' class='line'>{0}</a>{1}\n",
> + n + 1, line
> ));
> - syntect::html::append_highlighted_html_for_styled_line(
> - &regions[..],
> - syntect::html::IncludeBackground::IfDifferent(bg),
> - &mut output,
> - );
> }
> output.push_str("</pre>\n");
>  
> diff --git a/templates/static/style.css b/templates/static/style.css
> index f65d706..61e9d25 100644
> --- a/templates/static/style.css
> +++ b/templates/static/style.css
> @@ -1,10 +1,8 @@
> body {
> padding: 0;
> - border-top: 3px solid black;
> margin: 0;
> font-family: "Archivo", Helvetica, Arial, Sans-serif;
> word-wrap: break-word;
> - background-color: white;
> line-height: 1.5;
> }
>  
> @@ -12,10 +10,6 @@ body {
> max-width: 80ch;
> }
>  
> -a:visited {
> - color: blue;
> -}
> -
> .repo-last-updated {
> font-style: italic;
> }
> @@ -36,7 +30,7 @@ a:visited {
> text-align: center;
> font-style: italic;
> font-size: .9rem;
> - border-top: 1px solid black;
> + border-top: 1px solid;
> }
>  
> .line {
> @@ -53,10 +47,6 @@ a:visited {
> user-select: none; /* Non-prefixed version, currently */
> }
>  
> -:target {
> - background: #FFFACD;
> -}
> -
> .clone-url {
> font-family: "Roboto Mono", monospace;
> -webkit-user-select: all; /* Safari */
> @@ -64,41 +54,30 @@ a:visited {
> text-align: right;
> padding-left: 2px;
> padding-right: 2px;
> - display:inline-block
> + display: inline-block
> }
>  
> hr.thin {
> border: 0;
> height: 0;
> - /* top border for light color scheme */
> - border-top: 1px solid rgba(0, 0, 0, 0.1);
> - /* bottom border for dark color scheme */
> - border-bottom: 1px solid rgba(255, 255, 255, 0.3);
> + border-top: 1px solid;
> }
>  
> h1, h2, h3 {
> - margin: 0px;
> + margin: 0;
> }
>  
> pre {
> line-height: 1.2;
> font-size: 1rem;
> overflow: auto;
> - margin: 0px;
> - padding: 0px;
> -}
> -
> -tr:hover {
> - background-color: #f0f0f0;
> -}
> -
> -a:hover {
> - text-decoration: none;
> + margin: 0;
> + padding: 0;
> }
>  
> td {
> white-space: nowrap;
> - margin: 0px;
> + margin: 0;
> border-style:hidden;
> padding: 0;
> }
> @@ -112,20 +91,18 @@ table {
> }
>  
> #navbar {
> - /* background-color: #ededed; */
> - padding-left: 2ch;
> - padding-right: 2ch;
> + padding-left: 2ch;
> + padding-right: 2ch;
> }
>  
> .links {
> - background-color: #e8e8e8;
> - display: block;
> - padding-left: 2px;
> + display: block;
> + padding-left: 2px;
> }
>  
> .main {
> - padding-left: 2ch;
> - padding-right: 2ch;
> + padding-left: 2ch;
> + padding-right: 2ch;
> }
>  
>  
> @@ -139,17 +116,120 @@ table {
> }
> }
>  
> +/* for code highlighting */
> +
> +.markup.italic {
> + font-style: italic;
> +}
> +
> +.markup.bold {
> + font-weight: bold;
> +}
> +
> +/*
> +color scheme: Solarized
> +most of these classes are used by syntect
> +
> +Light is the default color scheme, not using a media query for browser
> support.
> +*/
> +/* TODO simplify, e.g. merge CSS classes. */
> +
> +.storage.modifier, .meta.scope.for-in-loop.shell,
> .variable.other.loop.shell, .meta.scope.case-block.shell,
> .meta.scope.case-body.shell {
> + color: #586e75; /* Solarized base01 */
> +}
> +
> +body, .code, .keyword.operator.comparison,
> .keyword.operator.assignment, .keyword.operator.arithmetic,
> .meta.brace.round, .meta.brace.curly, .punctuation.section,
> .punctuation.section.block, .punctuation.definition.parameters,
> .punctuation.section.group, .meta.selector.css, .text.html.basic,
> .meta.tag.other.html, .text.html.basic, .meta.tag.any.html,
> .text.html.basic, .meta.tag.block.any, .text.html.basic,
> .meta.tag.inline.any, .text.html.basic, .meta.tag.structure.any.html,
> .text.html.basic, .source.js.embedded.html,
> .punctuation.separator.key-value.html, .variable.other.readwrite.js,
> .variable.other.object.js, .variable.other.constant.js {
> + color: #657b83; /* Solarized base00 */
> +}
> +
> +hr.thin {
> + border-top-color: #657b83; /* Solarized base00 */
> +}
> +
> +.punctuation.definition.string {
> + color: #839496; /* Solarized base0 */
> +}
> +
> +.comment, .meta.documentation, .punctuation.definition.tag.html,
> .punctuation.definition.tag.begin, .punctuation.definition.tag.end,
> .meta.diff, .meta.diff.header,
> .constant.numeric.line-number.find-in-files {
> + color: #93a1a1; /* Solarized base1 */
> +}
> +
> +:target, tr:hover, .links, .meta.paragraph.markdown,
> .meta.dummy.line-break {
> + background-color: #eee8d5; /* Solarized base2 */
> +}
> +
> +body, .code {
> + background-color: #fdf6e3; /* Solarized base3 */
> +}
> +
> +.variable.function, .keyword.control.class, .entity.name,
> .entity.name.class, .entity.name.type.class,
> .entity.other.attribute-name, .entity.name.function, .constant,
> .constant.language, .meta.preprocessor, .support.constant.color,
> .invalid.deprecated.color.w3c-non-standard-color-name.scss,
> .entity.name.tag.css, .entity.name.tag.scss, .source.less,
> .keyword.control.html.elements, .source.sass, .keyword.control.untitled,
> .entity.other.attribute-name.class, .entity.other.attribute-name.id,
> .text.html.basic, .entity.other.attribute-name.html, .meta.tag.xml,
> .entity.other.attribute-name, .variable.other.constant.ruby,
> .meta.array, .support.function.construct.php, .meta.group.braces.tex,
> .string.other.math.tex, .string.other.math.tex,
> .support.type.exception.python, .markup.heading,
> .punctuation.definition.heading.markdown, .markup.changed.git_gutter {
> + color: #b58900; /* Solarized yellow */
> +}
> +
> +.meta.import, .keyword, .keyword.control.import,
> .keyword.control.import.from, .keyword.other.import,
> .keyword.control.at-rule.include, .keyword.control.at-rule.import,
> .entity.name.section, .constant.character, .constant.other,
> .support.type.exception, .keyword.other.special-method,
> .keyword.other.special-method.ruby,
> .entity.name.function.preprocessor.c, .meta.preprocessor.c.include,
> .meta.preprocessor.macro.c, .variable.parameter.function.latex,
> .support.function.section.latex {
> + color: #cb4b16; /* Solarized orange */
> +}
> +
> +.constant.character.escape, .support.function.construct,
> .keyword.other.new, .punctuation.separator.continuation,
> .other.package.exclude, .other.remove, .punctuation.section.group.tex,
> .punctuation.definition.arguments.begin.latex,
> .punctuation.definition.arguments.end.latex,
> .punctuation.definition.arguments.latex,
> .punctuation.definition.constant.math.tex,
> .punctuation.definition.string.begin.tex,
> .punctuation.definition.string.end.tex,
> .variable.parameter.definition.label.latex,
> .punctuation.definition.logical-expression.shell, .markup.deleted,
> .markup.deleted.git_gutter {
> + color: #dc322f; /* Solarized red */
> +}
> +
> +.variable.language {
> + color: #d33682; /* Solarized magenta */
> +}
> +
> +.constant.numeric, .constant.other.reference.link.markdown {
> + color: #6c71c4; /* Solarized violet */
> +}
> +
> +a, .variable, .entity.other.inherited-class, .entity.name.tag,
> .storage.type, .meta.brace.square, .punctuation.section.brackets,
> .entity.other.attribute-name.pseudo-element,
> .entity.other.attribute-name.tag.pseudo-element,
> .entity.other.attribute-name.pseudo-class,
> .entity.other.attribute-name.tag.pseudo-class, .support.function.perl,
> .meta.diff.range {
> + color: #268bd2; /* Solarized blue */
> +}
> +
> +.string, .string.regexp, .string.quoted.double, .string.quoted.single,
> .constant.other.symbol.ruby, .meta.preprocessor.c.include,
> .string.quoted.other.lt-gt.include.c, .meta.preprocessor.c.include,
> .punctuation.definition.string.begin.c, .meta.preprocessor.c.include,
> .punctuation.definition.string.end.c, .other.add, .text.tex.latex,
> .constant.other.math.tex, .constant.other.general.math.tex,
> .constant.other.general.math.tex, .constant.character.math.tex,
> .keyword.control.label.latex, .text.tex.latex,
> .constant.other.general.math.tex, .support.function.general.tex,
> .keyword.control.ref.latex, .markup.changed,
> .markup.underline.link.markdown, .meta.link.reference,
> .constant.other.reference.link.markdown,
> .entity.name.filename.find-in-files {
> + color: #2aa198; /* Solarized cyan */
> +}
> +
> +.keyword, .storage, .support, .support.type, .support.class,
> .punctuation.definition.variable, .support.function,
> .keyword.other.special-method.ruby, .support.function.be.latex,
> .storage.type.class.python, .storage.type.function.python,
> .storage.modifier.global.python, .storage.modifier.c++,
> .markup.inserted, .markup.quote, .markup.inserted.git_gutter {
> + color: #859900; /* Solarized green */
> +}
> +
> +.invalid {
> + background-color: #ec9489;
> +}
> +
> +/* Dark colour scheme for browsers that support it. */
> +
> @media (prefers-color-scheme: dark) {
> - body {
> - background: #212529;
> - color: #f8f9fa;
> + .storage.modifier, .meta.scope.for-in-loop.shell,
> .variable.other.loop.shell, .meta.scope.case-block.shell,
> .meta.scope.case-body.shell {
> + color: #93a1a1; /* Solarized base1 */
> + }
> +
> + body, .code, .keyword.operator.comparison,
> .keyword.operator.assignment, .keyword.operator.arithmetic,
> .meta.brace.round, .meta.brace.curly, .punctuation.section,
> .punctuation.section.block, .punctuation.definition.parameters,
> .punctuation.section.group, .meta.selector.css, .text.html.basic,
> .meta.tag.other.html, .text.html.basic, .meta.tag.any.html,
> .text.html.basic, .meta.tag.block.any, .text.html.basic,
> .meta.tag.inline.any, .text.html.basic, .meta.tag.structure.any.html,
> .text.html.basic, .source.js.embedded.html,
> .punctuation.separator.key-value.html, .variable.other.readwrite.js,
> .variable.other.object.js, .variable.other.constant.js {
> + color: #839496; /* Solarized base0 */
> + }
> +
> + hr.thin {
> + border-top-color: #839496; /* Solarized base0 */
> + }
> +
> + .punctuation.definition.string {
> + color: #657b83; /* Solarized base00 */
> + }
> +
> + .comment, .meta.documentation, .punctuation.definition.tag.html,
> .punctuation.definition.tag.begin, .punctuation.definition.tag.end,
> .meta.diff, .meta.diff.header,
> .constant.numeric.line-number.find-in-files {
> + color: #586e75; /* Solarized base01 */
> + }
> +
> + :target, tr:hover, .links, .meta.paragraph.markdown,
> .meta.dummy.line-break {
> + background-color: #073642; /* Solarized base02 */
> }
>  
> - :target {
> - background: #ffffff;
> + body, .code {
> + background-color: #002b36; /* Solarized base03 */
> }
>  
> - tr:hover {
> - background-color: #0f0f0f;
> + .invalid {
> + background-color: #6e2e32;
> }
> }
> --
> 2.20.1

Re: [PATCH mygit 3/3] caching for static resources

Details
Message ID
<CA94H9C49HUO.30OIMANX8NJ0W@debian-alex>
In-Reply-To
<20210328161130.1161-4-johann@qwertqwefsday.eu> (view parent)
DKIM signature
fail
Download raw message
DKIM signature: fail
Interesting, is there no Tide library to serve a file that includes the 405
handling already?

On Sun Mar 28, 2021 at 9:11 AM PDT, Johann Galle wrote:
> From: Johann150 <johann@qwertqwefsday.eu>
>
> ---
> src/errorpage.rs | 29 +++++++++----
> src/main.rs | 106 ++++++++++++++++++++++++++++++++++++++++-------
> 2 files changed, 112 insertions(+), 23 deletions(-)
>
> diff --git a/src/errorpage.rs b/src/errorpage.rs
> index a1436d3..f6995f6 100644
> --- a/src/errorpage.rs
> +++ b/src/errorpage.rs
> @@ -15,24 +15,35 @@ pub struct ErrorToErrorpage;
> impl<State: Clone + Send + Sync + 'static> Middleware<State> for
> ErrorToErrorpage {
> async fn handle(&self, req: Request<State>, next: Next<'_, State>) ->
> tide::Result {
> let resource = req.url().path().to_string();
> + let method = req.method();
> let mut response = next.run(req).await;
> if let Some(err) = response.take_error() {
> let status = err.status();
> - response = ErrorTemplate {
> - resource,
> - status,
> - message: err.into_inner().to_string(),
> +
> + if method == tide::http::Method::Head {
> + // the server MUST NOT send a message body in the response
> + // - RFC 7231 § 4.3.2
> + response.take_body();
> + } else {
> + response = ErrorTemplate {
> + resource,
> + status,
> + message: err.into_inner().to_string(),
> + }
> + .into();
> + response.set_status(status);
> }
> - .into();
> +
> if status == 405 {
> // The origin server MUST generate an Allow header field in
> // a 405 response containing a list of the target
> - // resource's currently supported methods. - RFC 7231§6.5.5
> + // resource's currently supported methods.
> + // - RFC 7231 § 6.5.5
> //
> - // We only ever support GET requests.
> - response.insert_header("Allow", "GET");
> + // We only ever support GET or HEAD requests.
> + // tide adds support for HEAD automatically if we implement GET
> + response.insert_header("Allow", "GET, HEAD");
> }
> - response.set_status(status);
> }
>  
> Ok(response)
> diff --git a/src/main.rs b/src/main.rs
> index 2ba9f68..5bee9fb 100644
> --- a/src/main.rs
> +++ b/src/main.rs
> @@ -3,7 +3,8 @@ use askama::Template;
> use git2::{Commit, Diff, DiffDelta, Reference, Repository, Tree,
> TreeEntry};
> use once_cell::sync::Lazy;
> use serde::Deserialize;
> -use std::fs;
> +use std::fs::{self, File};
> +use std::io::Read;
> use std::path::Path;
> use std::str;
> use syntect::parsing::SyntaxSet;
> @@ -468,10 +469,7 @@ async fn git_data(req: Request<()>) -> tide::Result
> {
> } else if !path.is_file() {
> // Either the requested resource does not exist or it is not
> // a file, i.e. a directory.
> - Err(tide::Error::from_str(
> - 404,
> - "The file you tried to access does not exist.",
> - ))
> + Err(tide::Error::from_str(404, "This page does not exist."))
> } else {
> // ok - inside the repo directory
> let mut resp = tide::Response::new(200);
> @@ -488,6 +486,89 @@ async fn git_data(req: Request<()>) -> tide::Result
> {
> }
> }
>  
> +/// Serve a file from ./templates/static/
> +async fn static_resource(req: Request<()>) -> tide::Result {
> + use tide::http::conditional::{IfModifiedSince, LastModified};
> +
> + // only use a File handle here because we might not need to load the
> file
> + let file_mime_option = match req.url().path() {
> + "/style.css" => Some((
> + File::open("templates/static/style.css").unwrap(),
> + tide::http::mime::CSS,
> + )),
> + "/robots.txt" => Some((
> + File::open("templates/static/robots.txt").unwrap(),
> + tide::http::mime::PLAIN,
> + )),
> + _ => None,
> + };
> +
> + match file_mime_option {
> + Some((mut file, mime)) => {
> + let metadata = file.metadata().unwrap();
> + let last_modified = metadata.modified().unwrap();
> +
> + let header = IfModifiedSince::from_headers(&req).unwrap();
> +
> + // check cache validating headers
> + if matches!(header, Some(date) if IfModifiedSince::new(last_modified)
> <= date) {
> + // the file has not changed
> + let mut response = Response::new(304);
> + response.set_content_type(mime);
> + LastModified::new(last_modified).apply(&mut response);
> +
> + /*
> + A server MAY send a Content-Length header field in a 304
> + response to a conditional GET request; a server MUST NOT send
> + Content-Length in such a response unless its field-value equals
> + the decimal number of octets that would have been sent in the
> + payload body of a 200 response to the same request.
> + - RFC 7230 § 3.3.2
> + */
> + response.insert_header("Content-Length", metadata.len().to_string());
> +
> + return Ok(response);
> + }
> +
> + let mut response = Response::new(200);
> +
> + match req.method() {
> + tide::http::Method::Head => {
> + /*
> + A server MAY send a Content-Length header field in a
> + response to a HEAD request; a server MUST NOT send
> + Content-Length in such a response unless its field-value
> + equals the decimal number of octets that would have been
> + sent in the payload body of a response if the same request
> + had used the GET method.
> + - RFC 7230 § 3.3.2
> + */
> + response.insert_header(
> + "Content-Length",
> + file.metadata().unwrap().len().to_string(),
> + );
> + }
> + tide::http::Method::Get => {
> + // load the file from disk
> + let mut content = String::new();
> + file.read_to_string(&mut content).unwrap();
> + response.set_body(content);
> + }
> + _ => return Err(tide::Error::from_str(405, "")),
> + }
> +
> + response.set_content_type(mime);
> + LastModified::new(last_modified).apply(&mut response);
> + Ok(response)
> + }
> + None if req.method() == tide::http::Method::Get => {
> + Err(tide::Error::from_str(404, "This page does not exist."))
> + }
> + // issue a 405 error since this is used as the catchall
> + None => Err(tide::Error::from_str(405, "")),
> + }
> +}
> +
> mod filters {
> use super::*;
>  
> @@ -554,10 +635,7 @@ async fn main() -> Result<(), std::io::Error> {
> let mut app = tide::new();
> app.with(errorpage::ErrorToErrorpage);
> app.at("/").get(index);
> - app.at("/robots.txt")
> - .serve_file("templates/static/robots.txt")?; // TODO configurable
> - app.at("/style.css")
> - .serve_file("templates/static/style.css")?; // TODO configurable
> +
> app.at("/:repo_name").get(repo_home);
> app.at("/:repo_name/").get(repo_home);
>  
> @@ -566,17 +644,17 @@ async fn main() -> Result<(), std::io::Error> {
> app.at("/:repo_name/HEAD").get(git_data);
> app.at("/:repo_name/objects/*obj").get(git_data);
>  
> + // web pages
> app.at("/:repo_name/commit/:commit").get(repo_commit);
> app.at("/:repo_name/refs").get(repo_refs);
> app.at("/:repo_name/log").get(repo_log);
> - app.at("/:repo_name/log/:ref").get(repo_log); // ref optional
> + app.at("/:repo_name/log/:ref").get(repo_log); // ref is optional
> app.at("/:repo_name/tree").get(repo_tree);
> - app.at("/:repo_name/tree/:ref").get(repo_tree);
> + app.at("/:repo_name/tree/:ref").get(repo_tree); // ref is optional
> app.at("/:repo_name/tree/:ref/item/*object_name")
> .get(repo_file);
> - app.at("*")
> - .get(|_| async { Result::<Response,
> tide::Error>::Err(tide::Error::from_str(404, "This page does not
> exist.")) })
> - .all(|_| async { Result::<Response,
> tide::Error>::Err(tide::Error::from_str(405, "This method is not
> allowed.")) });
> +
> + app.at("*").all(static_resource);
> // Raw files, patch files
> app.listen(format!("[::]:{}", CONFIG.port)).await?;
> Ok(())
> --
> 2.20.1

Re: [PATCH mygit 3/3] caching for static resources

Johann Galle
Details
Message ID
<bd4608c7-6d8b-eab6-6694-438610ae644c@qwertqwefsday.eu>
In-Reply-To
<CA94H9C49HUO.30OIMANX8NJ0W@debian-alex> (view parent)
DKIM signature
pass
Download raw message
On 28.03.2021 18:25, alex wennerberg wrote:
> Interesting, is there no Tide library to serve a file that includes the 
405
> handling already?

I did not find something like that. But I also almost added the `time` library before discovering the `IfModifiedSince`. Maybe you can find something?

Re: [PATCH mygit 3/3] caching for static resources

Details
Message ID
<CA9EELZY245H.NLU03T35QXW1@debian-alex>
In-Reply-To
<bd4608c7-6d8b-eab6-6694-438610ae644c@qwertqwefsday.eu> (view parent)
DKIM signature
fail
Download raw message
DKIM signature: fail
I'll take a look. I've been doing much less open source work lately,
limiting it to about an hour a day after work, so it may take me a bit

Alex

On Sun Mar 28, 2021 at 2:41 PM PDT, Johann Galle wrote:
> On 28.03.2021 18:25, alex wennerberg wrote:
> > Interesting, is there no Tide library to serve a file that includes the 
> 405
> > handling already?
>
> I did not find something like that. But I also almost added the `time`
> library before discovering the `IfModifiedSince`. Maybe you can find
> something?
Reply to thread Export thread (mbox)