feat: HTML default page
This commit is contained in:
parent
4158c1cf62
commit
e1655edd83
14 changed files with 408 additions and 10 deletions
|
@ -11,7 +11,7 @@ docker/
|
|||
*.iml
|
||||
|
||||
# Git folder
|
||||
.git
|
||||
# .git
|
||||
.gitea
|
||||
.gitlab
|
||||
.github
|
||||
|
|
|
@ -144,6 +144,9 @@ jobs:
|
|||
file: "docker/Dockerfile"
|
||||
build-args: |
|
||||
CONDUWUIT_VERSION_EXTRA=${{ env.COMMIT_SHORT_SHA }}
|
||||
COMMIT_SHA=${{ github.sha }})
|
||||
REMOTE_URL=${{github.event.repository.html_url }}
|
||||
REMOTE_COMMIT_URL=${{github.event.head_commit.url }}
|
||||
platforms: ${{ matrix.platform }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
annotations: ${{ steps.meta.outputs.annotations }}
|
||||
|
|
64
Cargo.lock
generated
64
Cargo.lock
generated
|
@ -109,6 +109,48 @@ version = "1.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dbc3a507a82b17ba0d98f6ce8fd6954ea0c8152e98009d36a40d8dcc8ce078a"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "assign"
|
||||
version = "1.1.1"
|
||||
|
@ -415,6 +457,15 @@ version = "1.7.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3"
|
||||
|
||||
[[package]]
|
||||
name = "basic-toml"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.69.5"
|
||||
|
@ -904,6 +955,7 @@ dependencies = [
|
|||
"conduwuit_api",
|
||||
"conduwuit_core",
|
||||
"conduwuit_service",
|
||||
"conduwuit_web",
|
||||
"const-str",
|
||||
"futures",
|
||||
"http",
|
||||
|
@ -961,6 +1013,18 @@ dependencies = [
|
|||
"webpage",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_web"
|
||||
version = "0.5.0-rc.5"
|
||||
dependencies = [
|
||||
"askama",
|
||||
"axum",
|
||||
"futures",
|
||||
"rand 0.8.5",
|
||||
"thiserror 2.0.12",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console-api"
|
||||
version = "0.8.1"
|
||||
|
|
|
@ -626,6 +626,11 @@ package = "conduwuit_macros"
|
|||
path = "src/macros"
|
||||
default-features = false
|
||||
|
||||
[workspace.dependencies.conduwuit-web]
|
||||
package = "conduwuit_web"
|
||||
path = "src/web"
|
||||
default-features = false
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Release profiles
|
||||
|
|
|
@ -111,14 +111,112 @@ RUN mkdir /out
|
|||
|
||||
FROM toolchain AS builder
|
||||
|
||||
|
||||
# Get source
|
||||
COPY . .
|
||||
|
||||
# Conduwuit version info
|
||||
ARG COMMIT_SHA=
|
||||
ARG SHORT_COMMIT_SHA=
|
||||
ARG REMOTE_URL=
|
||||
ARG CONDUWUIT_VERSION_EXTRA=
|
||||
ENV COMMIT_SHA=$COMMIT_SHA
|
||||
ENV SHORT_COMMIT_SHA=$SHORT_COMMIT_SHA
|
||||
ENV REMOTE_URL=$REMOTE_URL
|
||||
ENV CONDUWUIT_VERSION_EXTRA=$CONDUWUIT_VERSION_EXTRA
|
||||
RUN <<EOF
|
||||
if [ -z "${CONDUWUIT_VERSION_EXTRA}" ]; then
|
||||
echo "CONDUWUIT_VERSION_EXTRA='$(set -e; git rev-parse --short ${COMMIT_SHA:-HEAD} || echo unknown revision)'" >> /etc/environment
|
||||
|
||||
# Calculate version info from git if not provided via ARGs
|
||||
# and write all relevant vars to /etc/environment
|
||||
RUN <<'EOF'
|
||||
set -e # Exit on error
|
||||
|
||||
# Use temp variables to store calculated values
|
||||
calculated_commit_sha=""
|
||||
calculated_remote_url=""
|
||||
calculated_version_extra=""
|
||||
|
||||
# --- COMMIT_SHA ---
|
||||
# Calculate COMMIT_SHA if ENV var (from ARG) is empty
|
||||
if [ -z "${COMMIT_SHA}" ]; then
|
||||
# Try to get short commit hash from git
|
||||
calculated_commit_sha=$(git rev-parse HEAD 2>/dev/null || echo "")
|
||||
if [ -n "${calculated_commit_sha}" ]; then
|
||||
echo "COMMIT_SHA='${calculated_commit_sha}'" >> /etc/environment
|
||||
fi
|
||||
else
|
||||
# Ensure ARG-provided value is in /etc/environment
|
||||
echo "COMMIT_SHA='${COMMIT_SHA}'" >> /etc/environment
|
||||
fi
|
||||
|
||||
|
||||
if [ -z "${SHORT_COMMIT_SHA}" ]; then
|
||||
# Try to get short commit hash from git
|
||||
calculated_short_commit_sha=$(git rev-parse --short HEAD 2>/dev/null || echo "")
|
||||
if [ -n "${calculated_short_commit_sha}" ]; then
|
||||
echo "SHORT_COMMIT_SHA='${calculated_short_commit_sha}'" >> /etc/environment
|
||||
fi
|
||||
else
|
||||
# Ensure ARG-provided value is in /etc/environment
|
||||
echo "SHORT_COMMIT_SHA='${SHORT_COMMIT_SHA}'" >> /etc/environment
|
||||
fi
|
||||
|
||||
# --- REMOTE_URL ---
|
||||
# Calculate REMOTE_URL if ENV var (from ARG) is empty
|
||||
if [ -z "${REMOTE_URL}" ]; then
|
||||
# Try to get remote origin URL from git
|
||||
remote_url_raw=$(git config --get remote.origin.url 2>/dev/null || echo "")
|
||||
if [ -n "${remote_url_raw}" ]; then
|
||||
# Transform git URL (SSH or HTTPS) to web URL
|
||||
if [[ $remote_url_raw == "https://"* ]]; then
|
||||
# Already HTTPS, just remove .git suffix
|
||||
calculated_remote_url=$(echo "$remote_url_raw" | sed 's/\.git$//')
|
||||
else
|
||||
# Convert SSH URL to HTTPS URL
|
||||
calculated_remote_url=$(echo "$remote_url_raw" | sed 's/\.git$//' | sed 's/:/\//' | sed 's/^git@/https:\/\//')
|
||||
fi
|
||||
|
||||
# Write calculated web URL if transformation was successful
|
||||
if [ -n "${calculated_remote_url}" ]; then
|
||||
echo "REMOTE_URL='${calculated_remote_url}'" >> /etc/environment
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Ensure ARG-provided value is in /etc/environment (assume it's a valid web URL)
|
||||
echo "REMOTE_URL='${REMOTE_URL}'" >> /etc/environment
|
||||
# Use provided value for REMOTE_COMMIT_URL calculation below
|
||||
calculated_remote_url="${REMOTE_URL}"
|
||||
fi
|
||||
|
||||
# --- Determine effective values for subsequent calculations ---
|
||||
# Use ENV var value if set (from ARG), otherwise use calculated value
|
||||
effective_commit_sha="${COMMIT_SHA:-$calculated_commit_sha}"
|
||||
effective_short_commit_sha="${SHORT_COMMIT_SHA:-$calculated_short_commit_sha}"
|
||||
effective_remote_url="${REMOTE_URL:-$calculated_remote_url}"
|
||||
|
||||
# --- REMOTE_COMMIT_URL ---
|
||||
# Calculate and write REMOTE_COMMIT_URL if both components are available
|
||||
if [ -z "${REMOTE_COMMIT_URL}" ] && [ -n "${effective_remote_url}" ] && [ -n "${effective_commit_sha}" ]; then
|
||||
echo "REMOTE_COMMIT_URL='${effective_remote_url}/commit/${effective_commit_sha}'" >> /etc/environment
|
||||
else
|
||||
# Ensure ARG-provided value is in /etc/environment
|
||||
echo "REMOTE_COMMIT_URL='${REMOTE_COMMIT_URL}'" >> /etc/environment
|
||||
fi
|
||||
|
||||
# --- CONDUWUIT_VERSION_EXTRA ---
|
||||
# Calculate CONDUWUIT_VERSION_EXTRA if ENV var (from ARG) is empty
|
||||
if [ -z "${CONDUWUIT_VERSION_EXTRA}" ]; then
|
||||
# Use the effective short commit sha, fallback to "unknown revision"
|
||||
calculated_version_extra="${effective_short_commit_sha:-unknown revision}"
|
||||
# Handle case where commit sha calculation failed and ARG wasn't set
|
||||
if [ -z "${calculated_version_extra}" ]; then
|
||||
calculated_version_extra="unknown revision"
|
||||
fi
|
||||
echo "CONDUWUIT_VERSION_EXTRA='${calculated_version_extra}'" >> /etc/environment
|
||||
else
|
||||
# Ensure ARG-provided value is in /etc/environment
|
||||
echo "CONDUWUIT_VERSION_EXTRA='${CONDUWUIT_VERSION_EXTRA}'" >> /etc/environment
|
||||
fi
|
||||
|
||||
EOF
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
|
@ -127,8 +225,6 @@ ARG TARGETPLATFORM
|
|||
RUN cat /etc/environment
|
||||
RUN xx-cargo --print-target-triple
|
||||
|
||||
# Get source
|
||||
COPY . .
|
||||
|
||||
# Build the binary
|
||||
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
|
|
|
@ -130,6 +130,8 @@ buildDepsOnlyEnv =
|
|||
});
|
||||
|
||||
buildPackageEnv = {
|
||||
COMMIT_SHA = inputs.self.rev or inputs.self.dirtyRev or "";
|
||||
SHORT_COMMIT_SHA = inputs.self.shortRev or inputs.self.dirtyShortRev or "";
|
||||
CONDUWUIT_VERSION_EXTRA = inputs.self.shortRev or inputs.self.dirtyShortRev or "";
|
||||
} // buildDepsOnlyEnv // {
|
||||
# Only needed in static stdenv because these are transitive dependencies of rocksdb
|
||||
|
|
|
@ -103,6 +103,7 @@ conduwuit-admin.workspace = true
|
|||
conduwuit-api.workspace = true
|
||||
conduwuit-core.workspace = true
|
||||
conduwuit-service.workspace = true
|
||||
conduwuit-web.workspace = true
|
||||
const-str.workspace = true
|
||||
futures.workspace = true
|
||||
http.workspace = true
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use axum::{Router, response::IntoResponse, routing::get};
|
||||
use axum::{Router, response::IntoResponse};
|
||||
use conduwuit::Error;
|
||||
use conduwuit_api::router::{state, state::Guard};
|
||||
use conduwuit_service::Services;
|
||||
|
@ -11,7 +11,7 @@ pub(crate) fn build(services: &Arc<Services>) -> (Router, Guard) {
|
|||
let router = Router::<state::State>::new();
|
||||
let (state, guard) = state::create(services.clone());
|
||||
let router = conduwuit_api::router::build(router, &services.server)
|
||||
.route("/", get(it_works))
|
||||
.merge(conduwuit_web::build::<state::State>().with_state(()))
|
||||
.fallback(not_found)
|
||||
.with_state(state);
|
||||
|
||||
|
@ -21,5 +21,3 @@ pub(crate) fn build(services: &Arc<Services>) -> (Router, Guard) {
|
|||
async fn not_found(_uri: Uri) -> impl IntoResponse {
|
||||
Error::Request(ErrorKind::Unrecognized, "Not Found".into(), StatusCode::NOT_FOUND)
|
||||
}
|
||||
|
||||
async fn it_works() -> &'static str { "hewwo from conduwuit woof!" }
|
||||
|
|
32
src/web/Cargo.toml
Normal file
32
src/web/Cargo.toml
Normal file
|
@ -0,0 +1,32 @@
|
|||
[package]
|
||||
name = "conduwuit_web"
|
||||
categories.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
readme.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[lib]
|
||||
path = "mod.rs"
|
||||
crate-type = [
|
||||
"rlib",
|
||||
# "dylib",
|
||||
]
|
||||
|
||||
[features]
|
||||
|
||||
|
||||
[dependencies]
|
||||
askama = "0.14.0"
|
||||
|
||||
axum.workspace = true
|
||||
futures.workspace = true
|
||||
tracing.workspace = true
|
||||
rand.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
68
src/web/css/index.css
Normal file
68
src/web/css/index.css
Normal file
|
@ -0,0 +1,68 @@
|
|||
:root {
|
||||
color-scheme: light;
|
||||
--font-stack: sans-serif;
|
||||
|
||||
--background-color: #fff;
|
||||
--text-color: #000;
|
||||
|
||||
--bg: oklch(0.76 0.0854 317.27);
|
||||
--panel-bg: oklch(0.91 0.042 317.27);
|
||||
|
||||
--name-lightness: 0.45;
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
color-scheme: dark;
|
||||
--text-color: #fff;
|
||||
--bg: oklch(0.15 0.042 317.27);
|
||||
--panel-bg: oklch(0.24 0.03 317.27);
|
||||
|
||||
--name-lightness: 0.8;
|
||||
}
|
||||
|
||||
--c1: oklch(0.44 0.177 353.06);
|
||||
--c2: oklch(0.59 0.158 150.88);
|
||||
|
||||
--normal-font-size: 1rem;
|
||||
--small-font-size: 0.8rem;
|
||||
}
|
||||
|
||||
body {
|
||||
color: var(--text-color);
|
||||
font-family: var(--font-stack);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: var(--bg);
|
||||
background-image: linear-gradient(
|
||||
70deg,
|
||||
oklch(from var(--bg) l + 0.2 c h),
|
||||
oklch(from var(--bg) l - 0.2 c h)
|
||||
);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
width: min(clamp(24rem, 12rem + 40vw, 48rem), 100vw);
|
||||
border-radius: 15px;
|
||||
background-color: var(--panel-bg);
|
||||
padding-inline: 1.5rem;
|
||||
padding-block: 1rem;
|
||||
box-shadow: 0 0.25em 0.375em hsla(0, 0%, 0%, 0.1);
|
||||
}
|
||||
|
||||
.project-name {
|
||||
text-decoration: none;
|
||||
background: linear-gradient(
|
||||
130deg,
|
||||
oklch(from var(--c1) var(--name-lightness) c h),
|
||||
oklch(from var(--c2) var(--name-lightness) c h)
|
||||
);
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
filter: brightness(1.2);
|
||||
}
|
61
src/web/mod.rs
Normal file
61
src/web/mod.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
use askama::Template;
|
||||
use axum::{
|
||||
Router,
|
||||
http::{StatusCode, header},
|
||||
response::{Html, IntoResponse, Response},
|
||||
routing::get,
|
||||
};
|
||||
|
||||
pub fn build<S>() -> Router<()> { Router::new().route("/", get(index_handler)) }
|
||||
|
||||
async fn index_handler() -> Result<impl IntoResponse, WebError> {
|
||||
#[derive(Debug, Template)]
|
||||
#[template(path = "index.html.j2")]
|
||||
struct Tmpl<'a> {
|
||||
nonce: &'a str,
|
||||
}
|
||||
let nonce = rand::random::<u64>().to_string();
|
||||
|
||||
let template = Tmpl { nonce: &nonce };
|
||||
Ok((
|
||||
[(header::CONTENT_SECURITY_POLICY, format!("default-src 'none' 'nonce-{nonce}';"))],
|
||||
Html(template.render()?),
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
enum WebError {
|
||||
#[error("Failed to render template: {0}")]
|
||||
Render(#[from] askama::Error),
|
||||
}
|
||||
|
||||
impl IntoResponse for WebError {
|
||||
fn into_response(self) -> Response {
|
||||
#[derive(Debug, Template)]
|
||||
#[template(path = "error.html.j2")]
|
||||
struct Tmpl<'a> {
|
||||
nonce: &'a str,
|
||||
err: WebError,
|
||||
}
|
||||
|
||||
let nonce = rand::random::<u64>().to_string();
|
||||
|
||||
let status = match &self {
|
||||
| Self::Render(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
};
|
||||
let tmpl = Tmpl { nonce: &nonce, err: self };
|
||||
if let Ok(body) = tmpl.render() {
|
||||
(
|
||||
status,
|
||||
[(
|
||||
header::CONTENT_SECURITY_POLICY,
|
||||
format!("default-src 'none' 'nonce-{nonce}';"),
|
||||
)],
|
||||
Html(body),
|
||||
)
|
||||
.into_response()
|
||||
} else {
|
||||
(status, "Something went wrong").into_response()
|
||||
}
|
||||
}
|
||||
}
|
32
src/web/templates/_layout.html.j2
Normal file
32
src/web/templates/_layout.html.j2
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>{% block title %}Continuwuity{% endblock %}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<style type="text/css" nonce="{{ nonce }}">
|
||||
/*<![CDATA[*/
|
||||
{{ include_str !("css/index.css") | safe }}
|
||||
/*]]>*/
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main>{%~ block content %}{% endblock ~%}</main>
|
||||
{%~ block footer ~%}
|
||||
<footer>
|
||||
<p>Powered by <a href="https://continuwuity.org">Continuwuity</a>
|
||||
{%~ if let Some(version_info) = option_env!("CONDUWUIT_VERSION_EXTRA").or(option_env!("SHORT_COMMIT_SHA")) ~%}
|
||||
{%~ if let Some(url) = option_env!("REMOTE_COMMIT_URL").or(option_env!("REMOTE_URL")) ~%}
|
||||
(<a href="{{ url }}">{{ version_info }}</a>)
|
||||
{%~ else ~%}
|
||||
({{ version_info }})
|
||||
{%~ endif ~%}
|
||||
{%~ endif ~%}</p>
|
||||
</footer>
|
||||
{%~ endblock ~%}
|
||||
</body>
|
||||
|
||||
</html>
|
20
src/web/templates/error.html.j2
Normal file
20
src/web/templates/error.html.j2
Normal file
|
@ -0,0 +1,20 @@
|
|||
{% extends "_layout.html.j2" %}
|
||||
|
||||
{%- block title -%}
|
||||
Server Error
|
||||
{%- endblock -%}
|
||||
|
||||
{%- block content -%}
|
||||
<h1>
|
||||
{%- match err -%}
|
||||
{% else -%} 500: Internal Server Error
|
||||
{%- endmatch -%}
|
||||
</h1>
|
||||
|
||||
{%- match err -%}
|
||||
{% when WebError::Render(err) -%}
|
||||
<pre>{{ err }}</pre>
|
||||
{% else -%} <p>An error occurred</p>
|
||||
{%- endmatch -%}
|
||||
|
||||
{%- endblock -%}
|
16
src/web/templates/index.html.j2
Normal file
16
src/web/templates/index.html.j2
Normal file
|
@ -0,0 +1,16 @@
|
|||
{% extends "_layout.html.j2" %}
|
||||
{%- block content -%}
|
||||
<div class="orb"></div>
|
||||
<div class="panel">
|
||||
<h1>Welcome to <a class="project-name" href="https://continuwuity.org">Continuwuity</a>!</h1>
|
||||
<p>Continuwuity is successfully installed and working. </p>
|
||||
<p>To get started, you can:</p>
|
||||
<ul>
|
||||
<li>Read the <a href="https://continuwuity.org/introduction">documentation</a></li>
|
||||
<li>Join the <a href="https://continuwuity.org/community">community</a></li>
|
||||
<li>Log in with a <a href="https://matrix.org/ecosystem/clients/">client</a></li>
|
||||
<li>Ensure <a href="https://federationtester.matrix.org/">federation</a> works</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{%- endblock content -%}
|
Loading…
Add table
Add a link
Reference in a new issue