Compare commits
9 Commits
ad29538422
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
d74ca76e44
|
|||
|
031d0e39df
|
|||
|
b739780c13
|
|||
|
ad8183e10b
|
|||
|
ec1323a1b4
|
|||
|
3854c09577
|
|||
|
fc3806c334
|
|||
|
c29d5f5a9f
|
|||
|
12ebb3f8d9
|
35
.gitea/workflows/default.yaml
Normal file
35
.gitea/workflows/default.yaml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
name: build docker container automatically
|
||||||
|
run-name: docker build
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: get commit hash
|
||||||
|
id: get_hash
|
||||||
|
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: git.tmoron.fr
|
||||||
|
username: ${{ secrets.PUSH_USERNAME }}
|
||||||
|
password: ${{ secrets.PUSH_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v4
|
||||||
|
with:
|
||||||
|
context: "{{defaultContext}}:${{ input.path }}"
|
||||||
|
push: true
|
||||||
|
tags: git.tmoron.fr/${{ gitea.repository }}:latest
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -10,3 +10,6 @@ postgres/
|
|||||||
serveurhttp
|
serveurhttp
|
||||||
test
|
test
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
public/
|
||||||
|
assets/tailwind.css
|
||||||
|
|||||||
@ -3,6 +3,8 @@ name = "httpserver"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["tomoron <tomoron@student.42angouleme.fr>"]
|
authors = ["tomoron <tomoron@student.42angouleme.fr>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
description = "a rewrite of my http server in rust"
|
||||||
|
repository = "https://git.tmoron.fr/tom/httpserver"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|||||||
24
Dockerfile
Normal file
24
Dockerfile
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
FROM lewimbes/dioxus AS builder
|
||||||
|
|
||||||
|
RUN mkdir /build
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
LABEL stage="builder"
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
libpq-dev \
|
||||||
|
default-libmysqlclient-dev \
|
||||||
|
sqlite3 libsqlite3-dev && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN dx build -r
|
||||||
|
|
||||||
|
RUN cp /build/target/dx/httpserver/release/web /app -r
|
||||||
|
WORKDIR /app
|
||||||
|
RUN rm -rf /build
|
||||||
|
|
||||||
|
ENV IP="0.0.0.0"
|
||||||
|
|
||||||
|
CMD ["./server"]
|
||||||
@ -1,262 +0,0 @@
|
|||||||
/*! tailwindcss v4.1.5 | MIT License | https://tailwindcss.com */
|
|
||||||
@layer properties;
|
|
||||||
@layer theme, base, components, utilities;
|
|
||||||
@layer theme {
|
|
||||||
:root, :host {
|
|
||||||
--font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
|
||||||
'Noto Color Emoji';
|
|
||||||
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
|
|
||||||
monospace;
|
|
||||||
--color-blue-800: oklch(42.4% 0.199 265.638);
|
|
||||||
--color-zinc-900: oklch(21% 0.006 285.885);
|
|
||||||
--color-white: #fff;
|
|
||||||
--spacing: 0.25rem;
|
|
||||||
--text-4xl: 2.25rem;
|
|
||||||
--text-4xl--line-height: calc(2.5 / 2.25);
|
|
||||||
--font-weight-bold: 700;
|
|
||||||
--default-font-family: var(--font-sans);
|
|
||||||
--default-mono-font-family: var(--font-mono);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@layer base {
|
|
||||||
*, ::after, ::before, ::backdrop, ::file-selector-button {
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 0 solid;
|
|
||||||
}
|
|
||||||
html, :host {
|
|
||||||
line-height: 1.5;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
tab-size: 4;
|
|
||||||
font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji');
|
|
||||||
font-feature-settings: var(--default-font-feature-settings, normal);
|
|
||||||
font-variation-settings: var(--default-font-variation-settings, normal);
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
|
||||||
}
|
|
||||||
hr {
|
|
||||||
height: 0;
|
|
||||||
color: inherit;
|
|
||||||
border-top-width: 1px;
|
|
||||||
}
|
|
||||||
abbr:where([title]) {
|
|
||||||
-webkit-text-decoration: underline dotted;
|
|
||||||
text-decoration: underline dotted;
|
|
||||||
}
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
font-size: inherit;
|
|
||||||
font-weight: inherit;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
-webkit-text-decoration: inherit;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
b, strong {
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
|
||||||
code, kbd, samp, pre {
|
|
||||||
font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace);
|
|
||||||
font-feature-settings: var(--default-mono-font-feature-settings, normal);
|
|
||||||
font-variation-settings: var(--default-mono-font-variation-settings, normal);
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
small {
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
sub, sup {
|
|
||||||
font-size: 75%;
|
|
||||||
line-height: 0;
|
|
||||||
position: relative;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
sub {
|
|
||||||
bottom: -0.25em;
|
|
||||||
}
|
|
||||||
sup {
|
|
||||||
top: -0.5em;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
text-indent: 0;
|
|
||||||
border-color: inherit;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
:-moz-focusring {
|
|
||||||
outline: auto;
|
|
||||||
}
|
|
||||||
progress {
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
summary {
|
|
||||||
display: list-item;
|
|
||||||
}
|
|
||||||
ol, ul, menu {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
img, svg, video, canvas, audio, iframe, embed, object {
|
|
||||||
display: block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
img, video {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
button, input, select, optgroup, textarea, ::file-selector-button {
|
|
||||||
font: inherit;
|
|
||||||
font-feature-settings: inherit;
|
|
||||||
font-variation-settings: inherit;
|
|
||||||
letter-spacing: inherit;
|
|
||||||
color: inherit;
|
|
||||||
border-radius: 0;
|
|
||||||
background-color: transparent;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
:where(select:is([multiple], [size])) optgroup {
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
|
||||||
:where(select:is([multiple], [size])) optgroup option {
|
|
||||||
padding-inline-start: 20px;
|
|
||||||
}
|
|
||||||
::file-selector-button {
|
|
||||||
margin-inline-end: 4px;
|
|
||||||
}
|
|
||||||
::placeholder {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
|
|
||||||
::placeholder {
|
|
||||||
color: currentcolor;
|
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
|
||||||
color: color-mix(in oklab, currentcolor 50%, transparent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
textarea {
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
::-webkit-date-and-time-value {
|
|
||||||
min-height: 1lh;
|
|
||||||
text-align: inherit;
|
|
||||||
}
|
|
||||||
::-webkit-datetime-edit {
|
|
||||||
display: inline-flex;
|
|
||||||
}
|
|
||||||
::-webkit-datetime-edit-fields-wrapper {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
|
|
||||||
padding-block: 0;
|
|
||||||
}
|
|
||||||
:-moz-ui-invalid {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
button, input:where([type='button'], [type='reset'], [type='submit']), ::file-selector-button {
|
|
||||||
appearance: button;
|
|
||||||
}
|
|
||||||
::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
[hidden]:where(:not([hidden='until-found'])) {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@layer utilities {
|
|
||||||
.visible {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
.static {
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
.contents {
|
|
||||||
display: contents;
|
|
||||||
}
|
|
||||||
.flex {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.table {
|
|
||||||
display: table;
|
|
||||||
}
|
|
||||||
.h-screen {
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
.w-screen {
|
|
||||||
width: 100vw;
|
|
||||||
}
|
|
||||||
.transform {
|
|
||||||
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
|
||||||
}
|
|
||||||
.flex-col {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.bg-zinc-900 {
|
|
||||||
background-color: var(--color-zinc-900);
|
|
||||||
}
|
|
||||||
.p-1 {
|
|
||||||
padding: calc(var(--spacing) * 1);
|
|
||||||
}
|
|
||||||
.p-2 {
|
|
||||||
padding: calc(var(--spacing) * 2);
|
|
||||||
}
|
|
||||||
.px-2 {
|
|
||||||
padding-inline: calc(var(--spacing) * 2);
|
|
||||||
}
|
|
||||||
.text-4xl {
|
|
||||||
font-size: var(--text-4xl);
|
|
||||||
line-height: var(--tw-leading, var(--text-4xl--line-height));
|
|
||||||
}
|
|
||||||
.font-bold {
|
|
||||||
--tw-font-weight: var(--font-weight-bold);
|
|
||||||
font-weight: var(--font-weight-bold);
|
|
||||||
}
|
|
||||||
.text-blue-800 {
|
|
||||||
color: var(--color-blue-800);
|
|
||||||
}
|
|
||||||
.text-white {
|
|
||||||
color: var(--color-white);
|
|
||||||
}
|
|
||||||
.underline {
|
|
||||||
text-decoration-line: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@property --tw-rotate-x {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-rotate-y {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-rotate-z {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-skew-x {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-skew-y {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-font-weight {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@layer properties {
|
|
||||||
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
|
||||||
*, ::before, ::after, ::backdrop {
|
|
||||||
--tw-rotate-x: initial;
|
|
||||||
--tw-rotate-y: initial;
|
|
||||||
--tw-rotate-z: initial;
|
|
||||||
--tw-skew-x: initial;
|
|
||||||
--tw-skew-y: initial;
|
|
||||||
--tw-font-weight: initial;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,2 +1,2 @@
|
|||||||
mod component;
|
//mod component;
|
||||||
pub use component::*;
|
//pub use component::*;
|
||||||
|
|||||||
@ -12,9 +12,11 @@ use crate::config::ClientConfig;
|
|||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
#[cfg(feature = "server")]
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
#[cfg(feature = "server")]
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
|
||||||
|
|
||||||
@ -44,7 +46,7 @@ async fn upload_file(mut upload: FileStream) -> Result<String, HttpError> {
|
|||||||
|
|
||||||
let filename: String = loop {
|
let filename: String = loop {
|
||||||
let cur = random_string::generate(20, "ABCDEFGHIJKLMNOPQRTSTUVWXYZ0123456789");
|
let cur = random_string::generate(20, "ABCDEFGHIJKLMNOPQRTSTUVWXYZ0123456789");
|
||||||
if (!fs::exists(s_config.upload_folder.clone() + &cur).expect("can't check if file exists")) {
|
if !fs::exists(s_config.upload_folder.clone() + &cur).expect("can't check if file exists") {
|
||||||
break cur;
|
break cur;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -74,7 +76,7 @@ async fn upload_file(mut upload: FileStream) -> Result<String, HttpError> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if file.write(&bytes).is_err() { error == Some("failed write"); break; };
|
if file.write(&bytes).is_err() { error = Some("failed write"); break; };
|
||||||
},
|
},
|
||||||
Err(_) => { error = Some("unknown"); break; }
|
Err(_) => { error = Some("unknown"); break; }
|
||||||
}
|
}
|
||||||
@ -82,8 +84,8 @@ async fn upload_file(mut upload: FileStream) -> Result<String, HttpError> {
|
|||||||
|
|
||||||
match error {
|
match error {
|
||||||
Some(err)=> {
|
Some(err)=> {
|
||||||
file.sync_data();
|
let _ = file.sync_data();
|
||||||
fs::remove_file(s_config.upload_folder.clone() + &filename);
|
let _ = fs::remove_file(s_config.upload_folder.clone() + &filename);
|
||||||
HttpError::internal_server_error(err)?
|
HttpError::internal_server_error(err)?
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -137,7 +139,7 @@ pub fn build_table(files: Vec<(String, String, Option<Result<String, HttpError>>
|
|||||||
rsx! { p { "Upload failed, reason : {msg}" } }
|
rsx! { p { "Upload failed, reason : {msg}" } }
|
||||||
}
|
}
|
||||||
} }
|
} }
|
||||||
None => { rsx! { p { "Waiting for file to be uploaded" } } }
|
None => { rsx! { p { "Uploading ..." } } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
use std::fs::create_dir;
|
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus::fullstack::FileStream;
|
use dioxus::fullstack::FileStream;
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use httpserver::models::GetFile;
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
@ -15,6 +12,7 @@ use httpserver::schema;
|
|||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
use crate::config::ServerConfig;
|
use crate::config::ServerConfig;
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
|
||||||
@ -39,10 +37,10 @@ async fn download_file(id: String) -> Result<FileStream, HttpError> {
|
|||||||
use schema::file;
|
use schema::file;
|
||||||
let s_config = ServerConfig::load();
|
let s_config = ServerConfig::load();
|
||||||
|
|
||||||
let result = DB.with(|pool| schema::file::table.select((file::filename))
|
let result = DB.with(|pool| schema::file::table.select(file::filename)
|
||||||
.filter(file::stored_filename.eq(id.clone()))
|
.filter(file::stored_filename.eq(id.clone()))
|
||||||
.filter(file::deleted.eq(false))
|
.filter(file::deleted.eq(false))
|
||||||
.load::<(String)>(&mut pool.get().unwrap()));
|
.load::<String>(&mut pool.get().unwrap()));
|
||||||
|
|
||||||
if let Err(_) = result {
|
if let Err(_) = result {
|
||||||
return HttpError::internal_server_error("Database request failed");
|
return HttpError::internal_server_error("Database request failed");
|
||||||
|
|||||||
@ -1,20 +1,17 @@
|
|||||||
use std::time::SystemTime;
|
|
||||||
|
|
||||||
use chrono::DateTime;
|
use chrono::DateTime;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
|
||||||
use dioxus::fullstack::httperror;
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use httpserver::utils::byte_to_human_size;
|
use httpserver::utils::byte_to_human_size;
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use httpserver::models::GetFile;
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
use httpserver::DB;
|
use httpserver::DB;
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
use httpserver::schema;
|
use httpserver::schema;
|
||||||
@ -62,10 +59,15 @@ fn show_file_info(file_id: String, file_info: &FetchedInfo) -> Element {
|
|||||||
p { "Position in the deletion queue : ",
|
p { "Position in the deletion queue : ",
|
||||||
match file_info.deletion_pos {
|
match file_info.deletion_pos {
|
||||||
Some(pos) => pos.to_string(),
|
Some(pos) => pos.to_string(),
|
||||||
None => "unknown".to_string()
|
None => "files aren't deleted for a week after the time of upload".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
a { class: "height-20px text-blue-800 underline", href: "/upload/{file_id}/dl", "click here to download the file"}
|
a {
|
||||||
|
class: "height-20px text-blue-800 underline",
|
||||||
|
rel: "noopener noreferrer",
|
||||||
|
href: "/upload/{file_id}/dl",
|
||||||
|
"click here to download the file"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use httpserver::models::GetFile;
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
@ -9,17 +7,14 @@ use httpserver::DB;
|
|||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
use diesel::dsl;
|
use diesel::dsl;
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use httpserver::schema;
|
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
use crate::config::ServerConfig;
|
use crate::config::ServerConfig;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
use bigdecimal::{BigDecimal, ToPrimitive};
|
use bigdecimal::{BigDecimal, ToPrimitive};
|
||||||
|
|
||||||
use httpserver::utils::byte_to_human_size;
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
struct UploadServerStats {
|
struct UploadServerStats {
|
||||||
total_limit_soft: u64,
|
total_limit_soft: u64,
|
||||||
@ -43,8 +38,8 @@ async fn get_upload_stats() -> Result<UploadServerStats, HttpError> {
|
|||||||
_ => return HttpError::internal_server_error("wth ?")
|
_ => return HttpError::internal_server_error("wth ?")
|
||||||
};
|
};
|
||||||
|
|
||||||
let total_files = match DB.with(|pool| file::table.select((dsl::count(file::id)))
|
let total_files = match DB.with(|pool| file::table.select(dsl::count(file::id))
|
||||||
.first::<(i64)>(&mut pool.get().unwrap())) {
|
.first::<i64>(&mut pool.get().unwrap())) {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
_ => return HttpError::internal_server_error("wth ?")
|
_ => return HttpError::internal_server_error("wth ?")
|
||||||
};
|
};
|
||||||
@ -61,8 +56,12 @@ async fn get_upload_stats() -> Result<UploadServerStats, HttpError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_stats(stats : &UploadServerStats) -> Element {
|
fn render_stats(stats : &UploadServerStats) -> Element {
|
||||||
let soft_percentage = stats.used_space as f32 / stats.total_limit_soft as f32;
|
let mut soft_percentage = stats.used_space as f32 / stats.total_limit_soft as f32;
|
||||||
let hard_percentage = stats.used_space as f32 / stats.total_limit_hard as f32;
|
let mut hard_percentage = stats.used_space as f32 / stats.total_limit_hard as f32;
|
||||||
|
|
||||||
|
soft_percentage = (soft_percentage * 1000f32).round() / 1000f32;
|
||||||
|
hard_percentage = (hard_percentage * 1000f32).round() / 1000f32;
|
||||||
|
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
h1 {class: "text-4xl font-bold", "Server info"}
|
h1 {class: "text-4xl font-bold", "Server info"}
|
||||||
|
|||||||
@ -12,23 +12,23 @@ impl ServerConfig {
|
|||||||
pub fn load() -> Self {
|
pub fn load() -> Self {
|
||||||
Self {
|
Self {
|
||||||
upload_folder: "./test/".to_string(),
|
upload_folder: "./test/".to_string(),
|
||||||
db_url: std::env::var("DATABASE_URL").expect("missing DATABASE_URL"),
|
db_url: std::env::var("HTTPSERVER_DATABASE_URL").expect("missing HTTPSERVER_DATABASE_URL"),
|
||||||
|
|
||||||
upload_storage_limit_soft: 1024 * 1024 * 1024 * 200,
|
upload_storage_limit_soft: 1024 * 1024 * 1024 * 200,
|
||||||
upload_storage_limit_hard: 1024 * 1024 * 1024 * 300,
|
upload_storage_limit_hard: 1024 * 1024 * 1024 * 250,
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClientConfig {
|
pub struct ClientConfig {
|
||||||
pub upload_max_size: usize,
|
pub upload_max_size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientConfig {
|
impl ClientConfig {
|
||||||
pub fn load() -> Self {
|
pub fn load() -> Self {
|
||||||
Self {
|
Self {
|
||||||
upload_max_size: 1024 * 1024 * 1024 * 1, //1GB for testing
|
upload_max_size: 1024 * 1024 * 1024 * 50,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
use diesel::pg::PgConnection;
|
use diesel::pg::PgConnection;
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use diesel::prelude::*;
|
|
||||||
|
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
@ -18,17 +16,15 @@ pub mod schema;
|
|||||||
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
use diesel::r2d2::{ConnectionManager, Pool};
|
use diesel::r2d2::{ConnectionManager, Pool};
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use diesel::result::Error;
|
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
thread_local! {
|
thread_local! {
|
||||||
pub static DB: diesel::r2d2::Pool<ConnectionManager<PgConnection>> = {
|
pub static DB: Pool<ConnectionManager<PgConnection>> = {
|
||||||
let s_config = ServerConfig::load();
|
let s_config = ServerConfig::load();
|
||||||
let db_url = s_config.db_url.clone();
|
let db_url = s_config.db_url.clone();
|
||||||
|
|
||||||
let manager = ConnectionManager::<PgConnection>::new(&db_url);
|
let manager = ConnectionManager::<PgConnection>::new(&db_url);
|
||||||
diesel::r2d2::Pool::builder()
|
Pool::builder()
|
||||||
.build(manager)
|
.build(manager)
|
||||||
.unwrap_or_else(|_| panic!("Error creating pool for {}", db_url))
|
.unwrap_or_else(|_| panic!("Error creating pool for {}", db_url))
|
||||||
};
|
};
|
||||||
|
|||||||
30
src/main.rs
30
src/main.rs
@ -1,27 +1,38 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
use crate::components::upload::{FileInfo, UploadFile, UploadStats};
|
|
||||||
use tracing::Level;
|
use tracing::Level;
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
|
||||||
use crate::components::toast::ToastProvider;
|
use crate::components::toast::ToastProvider;
|
||||||
|
|
||||||
|
use crate::views::{Upload, UploadInfo, Home};
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
use crate::config::ServerConfig;
|
||||||
|
|
||||||
mod components;
|
mod components;
|
||||||
mod views;
|
mod views;
|
||||||
|
|
||||||
//#[derive(Debug, Clone, Routable, PartialEq)]
|
#[derive(Debug, Clone, Routable, PartialEq)]
|
||||||
//#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
//enum Route {
|
enum Route {
|
||||||
// #[route("/upload")]
|
#[route("/")]
|
||||||
// Upload { },
|
Home { },
|
||||||
//}
|
#[route("/upload/:file")]
|
||||||
|
UploadInfo { file: String },
|
||||||
|
#[route("/upload")]
|
||||||
|
Upload { },
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const FAVICON: Asset = asset!("/assets/favicon.ico");
|
const FAVICON: Asset = asset!("/assets/favicon.ico");
|
||||||
const TAILWIND_CSS: Asset = asset!("/assets/tailwind.css");
|
const TAILWIND_CSS: Asset = asset!("/assets/tailwind.css");
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
let _ = ServerConfig::load();
|
||||||
|
|
||||||
dioxus::logger::init(Level::INFO).expect("failed to init logger");
|
dioxus::logger::init(Level::INFO).expect("failed to init logger");
|
||||||
dioxus::launch(App);
|
dioxus::launch(App);
|
||||||
}
|
}
|
||||||
@ -34,10 +45,7 @@ fn App() -> Element {
|
|||||||
div {
|
div {
|
||||||
class: "h-screen w-screen bg-zinc-900 text-white",
|
class: "h-screen w-screen bg-zinc-900 text-white",
|
||||||
ToastProvider {
|
ToastProvider {
|
||||||
UploadFile { }
|
Router::<Route> {}
|
||||||
FileInfo {file: "ULI0GZWJQH9BGEZR1VZ1"}
|
|
||||||
UploadStats { }
|
|
||||||
// Router::<Route> {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
21
src/views/home.rs
Normal file
21
src/views/home.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
use crate::Route;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Home() -> Element {
|
||||||
|
rsx! {
|
||||||
|
div { class : "flex flex-col text-3xl px-2",
|
||||||
|
Link {
|
||||||
|
to : Route::Upload { },
|
||||||
|
class: "height-20px text-blue-700 underline py-1",
|
||||||
|
"Upload"
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
class: "height-20px text-blue-700 underline py-1",
|
||||||
|
href : "https://git.tmoron.fr/tom ",
|
||||||
|
"gitea"
|
||||||
|
}
|
||||||
|
p { class : "text-sm text-gray-600", "I know, you're impressed by my design skills." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +1,5 @@
|
|||||||
//mod upload;
|
mod upload;
|
||||||
//pub use upload::Upload;
|
pub use upload::{Upload, UploadInfo};
|
||||||
|
|
||||||
|
mod home;
|
||||||
|
pub use home::Home;
|
||||||
|
|||||||
@ -1,20 +1,19 @@
|
|||||||
use dioxus::{
|
use dioxus::prelude::*;
|
||||||
fullstack::{FileStream},
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
use crate::components::upload::{ FileInfo, UploadFile, UploadStats };
|
||||||
use crate::config::ServerConfig;
|
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use httpserver::models::{GetFile,NewFile};
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use diesel::prelude::*;
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use httpserver::DB;
|
|
||||||
|
|
||||||
|
|
||||||
use dioxus_primitives::toast::{
|
#[component]
|
||||||
ToastOptions,
|
pub fn Upload() -> Element {
|
||||||
consume_toast
|
rsx! {
|
||||||
};
|
UploadFile { }
|
||||||
|
UploadStats { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn UploadInfo(file: String) -> Element {
|
||||||
|
rsx! {
|
||||||
|
FileInfo{ file : file }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user