Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

editoast, front: host fonts for the map in editoast #10788

Merged
merged 3 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion editoast/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
target
*.snap.new
assets/sprites/*/sprites*
assets/sprites/*/sprites.*
assets/fonts/glyphs/*
7 changes: 6 additions & 1 deletion editoast/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ COPY --from=static_assets . /assets
#######################
# Build assets #
#######################
FROM alpine:latest AS editoast_assets
FROM ubuntu:latest AS editoast_assets
RUN apt update && apt install --yes wget
RUN wget https://github.com/flother/spreet/releases/download/v0.11.0/spreet-x86_64-unknown-linux-musl.tar.gz
RUN tar xvf spreet-x86_64-unknown-linux-musl.tar.gz --directory /usr/bin
RUN wget http://github.com/stadiamaps/sdf_font_tools/releases/download/cli-v1.4.2/build_pbf_glyphs.x86_64-unknown-linux-gnu -O /usr/bin/build_pbf_glyphs
RUN chmod +x /usr/bin/build_pbf_glyphs
COPY ./assets /assets
RUN /assets/sprites/generate-atlas.sh
RUN /assets/fonts/generate-glyphs.sh

######################
# Testing env: build #
Expand All @@ -44,6 +48,7 @@ ENV RUSTFLAGS="-Cinstrument-coverage -C target-feature=-crt-static -C link-arg=-
ENV LLVM_PROFILE_FILE="editoast-%p-%m.profraw"
RUN cargo chef cook --tests --recipe-path recipe.json
COPY . .
COPY --from=editoast_assets /assets /editoast/assets

#######################
# Running env : build #
Expand Down
2 changes: 2 additions & 0 deletions editoast/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ $ diesel migration run
# build the assets
$ cargo install spreet
$ ./assets/sprites/generate-atlas.sh
$ cargo install build_pbf_glyphs
$ ./assets/fonts/generate-glyphs.sh
# Build and run
$ cargo build
$ cargo run -- runserver
Expand Down
Binary file added editoast/assets/fonts/Roboto Bold.ttf
Binary file not shown.
Binary file not shown.
Binary file added editoast/assets/fonts/Roboto Condensed.ttf
Binary file not shown.
Binary file added editoast/assets/fonts/Roboto Italic.ttf
Binary file not shown.
Binary file added editoast/assets/fonts/Roboto Medium.ttf
Binary file not shown.
Binary file added editoast/assets/fonts/Roboto Regular.ttf
Binary file not shown.
Binary file added editoast/assets/fonts/SNCF.ttf
Binary file not shown.
11 changes: 11 additions & 0 deletions editoast/assets/fonts/generate-glyphs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/sh

# This script should be used to generate glyphs from ttf fonts.
# Those glyphs are used to display text on the map
# You will need build_pbf_glyphs, you can install it with:
# `$ cargo install build_pbf_glyphs`
set -e

fonts_directory=$(dirname "$(realpath "$0")")
echo "Converting fonts in ${fonts_directory} to glyphs"
build_pbf_glyphs "${fonts_directory}" "${fonts_directory}"/glyphs/
48 changes: 48 additions & 0 deletions editoast/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,29 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/InternalError'
/fonts/{font}/{glyph}:
get:
tags:
- fonts
summary: This endpoint is used by map libre to retrieve the fonts. They are separated by font and unicode block
parameters:
- name: font
in: path
description: Requested font
required: true
schema:
type: string
- name: glyph
in: path
description: Requested unicode block
required: true
schema:
type: string
responses:
'200':
description: Glyphs in PBF format of the font at the requested unicode block
'404':
description: Font not found
/health:
get:
responses:
Expand Down Expand Up @@ -4807,6 +4830,7 @@ components:
- $ref: '#/components/schemas/EditoastEditionErrorSplitTrackSectionBadOffset'
- $ref: '#/components/schemas/EditoastEditoastUrlErrorInvalidUrl'
- $ref: '#/components/schemas/EditoastElectricalProfilesErrorNotFound'
- $ref: '#/components/schemas/EditoastFontErrorsFileNotFound'
- $ref: '#/components/schemas/EditoastGeometryErrorUnexpectedGeometry'
- $ref: '#/components/schemas/EditoastGetObjectsErrorsDuplicateIdsProvided'
- $ref: '#/components/schemas/EditoastGetObjectsErrorsObjectIdNotFound'
Expand Down Expand Up @@ -4889,6 +4913,30 @@ components:
description: Generated error type for Editoast
discriminator:
propertyName: type
EditoastFontErrorsFileNotFound:
type: object
required:
- type
- status
- message
properties:
context:
type: object
required:
- file
properties:
file:
type: string
message:
type: string
status:
type: integer
enum:
- 404
type:
type: string
enum:
- editoast:fonts:FileNotFound
EditoastGeometryErrorUnexpectedGeometry:
type: object
required:
Expand Down
77 changes: 77 additions & 0 deletions editoast/src/views/fonts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use axum::extract::Path;
use axum::extract::Request;
use axum::response::IntoResponse;
use editoast_derive::EditoastError;
use thiserror::Error;
use tower::ServiceExt;
use tower_http::services::ServeFile;

use crate::client::get_dynamic_assets_path;
use crate::error::Result;

crate::routes! {
"/fonts/{font}/{glyph}" => fonts,
}

#[derive(Debug, Error, EditoastError)]
#[editoast_error(base_id = "fonts")]
enum FontErrors {
#[error("File '{file}' not found")]
#[editoast_error(status = 404)]
FileNotFound { file: String },
}

/// This endpoint is used by map libre to retrieve the fonts. They are separated by font and unicode block
#[utoipa::path(
get, path = "",
tag = "fonts",
params(
("font" = String, Path, description = "Requested font"),
("glyph" = String, Path, description = "Requested unicode block"),
),
responses(
(status = 200, description = "Glyphs in PBF format of the font at the requested unicode block"),
(status = 404, description = "Font not found"),
),
)]
async fn fonts(
Path((font, file_name)): Path<(String, String)>,
request: Request,
) -> Result<impl IntoResponse> {
let path = get_dynamic_assets_path().join(format!("fonts/glyphs/{font}/{file_name}"));

if !path.is_file() {
return Err(FontErrors::FileNotFound { file: file_name }.into());
}

Ok(ServeFile::new(&path).oneshot(request).await)
}

#[cfg(test)]
mod tests {
use crate::views::test_app::TestAppBuilder;

use super::*;
use axum::http::StatusCode;
use rstest::rstest;

#[rstest]
async fn test_font() {
let app = TestAppBuilder::default_app();
let request = app.get("/fonts/Roboto%20Bold/0-255.pbf");
let response = app.fetch(request).assert_status(StatusCode::OK);
assert_eq!("application/octet-stream", response.content_type());
let response = response.bytes();
let expected =
std::fs::read(get_dynamic_assets_path().join("fonts/glyphs/Roboto Bold/0-255.pbf"))
.unwrap();
assert_eq!(response, expected);
}

#[rstest]
async fn test_font_not_found() {
let app = TestAppBuilder::default_app();
let request = app.get("/fonts/Comic%20Sans/0-255.pbf");
app.fetch(request).assert_status(StatusCode::NOT_FOUND);
}
}
2 changes: 2 additions & 0 deletions editoast/src/views/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod authz;
mod documents;
pub mod electrical_profiles;
pub mod fonts;
pub mod infra;
mod layers;
mod openapi;
Expand Down Expand Up @@ -99,6 +100,7 @@ crate::routes! {
&authz,
&documents,
&electrical_profiles,
&fonts,
&infra,
&layers,
&projects,
Expand Down
3 changes: 3 additions & 0 deletions front/public/locales/en/errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
"electrical_profiles": {
"NotFound": "Electrical Profile Set '{{electrical_profile_set_id}}', could not be found"
},
"fonts": {
"FileNotFound": "File for the requested font not found"
},
"geometry": {
"UnexpectedGeometry": "Expected geometry {{expected}} but got {{actual}}"
},
Expand Down
3 changes: 3 additions & 0 deletions front/public/locales/fr/errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
"electrical_profiles": {
"NotFound": "Profil électrique '{{electrical_profile_set_id}}' non trouvé"
},
"fonts": {
"FileNotFound": "Fichier pour la police de charactère demandée non trouvé"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a typo : caractère instead of charactère

},
"geometry": {
"UnexpectedGeometry": "Géometrie {{expected}} attendue mais {{actual}} reçue"
},
Expand Down
2 changes: 1 addition & 1 deletion front/src/common/Map/Layers/blankStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const useMapBlankStyle = (): MapProps['mapStyle'] => {
name: 'Blank',
sources: {},
sprite,
glyphs: 'https://static.osm.osrd.fr/fonts/{fontstack}/{range}.pbf',
glyphs: `${window.location.origin}${baseURL}/fonts/{fontstack}/{range}.pbf`,
layers: [
{
id: 'emptyBackground',
Expand Down
15 changes: 15 additions & 0 deletions front/src/common/api/generatedEditoastApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const addTagTypes = [
'authz',
'documents',
'electrical_profiles',
'fonts',
'infra',
'rolling_stock',
'delimited_area',
Expand Down Expand Up @@ -138,6 +139,13 @@ const injectedRtkApi = api
}),
providesTags: ['electrical_profiles'],
}),
getFontsByFontAndGlyph: build.query<
GetFontsByFontAndGlyphApiResponse,
GetFontsByFontAndGlyphApiArg
>({
query: (queryArg) => ({ url: `/fonts/${queryArg.font}/${queryArg.glyph}` }),
providesTags: ['fonts'],
}),
getHealth: build.query<GetHealthApiResponse, GetHealthApiArg>({
query: () => ({ url: `/health` }),
}),
Expand Down Expand Up @@ -1169,6 +1177,13 @@ export type GetElectricalProfileSetByElectricalProfileSetIdLevelOrderApiResponse
export type GetElectricalProfileSetByElectricalProfileSetIdLevelOrderApiArg = {
electricalProfileSetId: number;
};
export type GetFontsByFontAndGlyphApiResponse = unknown;
export type GetFontsByFontAndGlyphApiArg = {
/** Requested font */
font: string;
/** Requested unicode block */
glyph: string;
};
export type GetHealthApiResponse = unknown;
export type GetHealthApiArg = void;
export type GetInfraApiResponse = /** status 200 All infras, paginated */ PaginationStats & {
Expand Down
Loading