From dcae2950e3b7427a1e98b88c4904ae6ddb53d151 Mon Sep 17 00:00:00 2001 From: Hubert Date: Thu, 1 Jul 2021 06:52:04 +0200 Subject: [PATCH] base --- Cargo.toml | 15 +++++ src/git.rs | 68 +++++++++++++++++++ src/ite.rs | 118 ++++++++++++++++++++++++++++++++ src/main.rs | 156 +++++++++++++++++++++++++++++++++++++++++++ templates/base.html | 11 +++ templates/git.html | 20 ++++++ templates/hello.html | 11 +++ 7 files changed, 399 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/git.rs create mode 100644 src/ite.rs create mode 100644 src/main.rs create mode 100644 templates/base.html create mode 100644 templates/git.html create mode 100644 templates/hello.html diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..7993af9 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "http-rs" +version = "0.1.0" +authors = ["hubert"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +actix-web = "3.3.2" +actix-session = "0.4.1" +actix-web-httpauth = "0.5.1" +askama = "0.10.5" +askama_actix = "0.11.1" +env_logger = "0.8.4" \ No newline at end of file diff --git a/src/git.rs b/src/git.rs new file mode 100644 index 0000000..b815786 --- /dev/null +++ b/src/git.rs @@ -0,0 +1,68 @@ +use std::fmt::{Display, Formatter, Result}; + +pub struct GitRepo {} + +impl GitRepo { + + pub fn new() -> GitRepo { + GitRepo{} + } + + pub async fn browse(&self, commit : &GitCommit, dir: &GitBrowseDir) -> Vec { + vec!(GitBrowseEntry::EGitDir(GitBrowseDir("src/".to_string())), GitBrowseEntry::EGitFile(GitBrowseFile("pom.xml".to_string()))) + } + +} + +#[derive(Debug)] +pub struct GitCommit (String); + +impl GitCommit { + pub fn new(s : String) -> GitCommit { + GitCommit(s) + } +} + +impl Display for GitCommit { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.0) + } +} + +#[derive(Debug)] +pub struct GitBrowseFile (String); +#[derive(Debug)] +pub struct GitBrowseDir (String); + +impl GitBrowseDir { + pub fn new(s : String) -> GitBrowseDir { + GitBrowseDir(s) + } +} + +impl Display for GitBrowseFile { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.0) + } +} + +impl Display for GitBrowseDir { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.0) + } +} + +#[derive(Debug)] +pub enum GitBrowseEntry { + EGitFile(GitBrowseFile), + EGitDir(GitBrowseDir) +} + +impl Display for GitBrowseEntry { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + match self { + GitBrowseEntry::EGitFile(file) => {write!(f, "{}", file)} + GitBrowseEntry::EGitDir(dir) => {write!(f, "{}", dir)} + } + } +} \ No newline at end of file diff --git a/src/ite.rs b/src/ite.rs new file mode 100644 index 0000000..111e3ce --- /dev/null +++ b/src/ite.rs @@ -0,0 +1,118 @@ +use std::ops::Deref; + +struct State{ + b : B, +} + +impl State { + fn set(&mut self, b : B) { + self.b = b + } + + // fn trace(&mut self, step : impl Fn(A, &B) -> (C, B)) -> impl FnMut(A) -> C { + // return |a| { + // let (c, b2) = step(a, &self.b); + // self.b = b2; + // return c; + // } + // } + + // fn get(&self) -> B { + // let bb = self.b; + // return self.b; + // } +} +struct StatefullFct{ + b : B, + f : F, +} + +impl StatefullFct { + fn truc(&mut self, a : A) -> C where F : FnMut(A, &B) -> (C, B) { + let (c, b) = (&mut self.f)(a, &self.b); + self.b = b; + return c; + } +} + +// fn trace(step : impl Fn(A, B) -> (C, B), b : B) -> impl FnMut(A) -> C { +// let mut bmut = b; +// return move |a| { +// let (c, b2) = step(a, bmut); +// bmut = b2; +// return c; +// } +// } + +// impl State{ +// fn get_fn(&mut self, mut f : impl FnMut(A, B) -> (C, B)) -> impl FnMut(A) -> C { +// return move |a| { +// let plop : B = self.0; +// let (c, b) = f(a, self.0); +// self.0 = b; +// return c; +// } +// } +// } + +pub fn map_accum(f : impl FnMut(A, &B) -> (C, B), b : B, ite : impl Iterator) -> impl Iterator { + let mut sf = StatefullFct { b, f }; + let ff = move |a| {sf.truc(a)}; + let res = ite.map(ff); + return res; +} + +pub struct MapAccum{ + ite : I, + f : F, + b : Option +} + +impl MapAccum { + fn last_state(self) -> B { + return self.b.unwrap(); + } +} + +impl, F : FnMut(A, B) -> (C, B), B> Iterator for MapAccum { + type Item = C; + + fn next(&mut self) -> Option { + self.ite.next().map(|a| { + let old_state = self.b.take().unwrap(); + let (c, b) = (self.f)(a, old_state); + self.b = Some(b); + return c; + }) + } +} + +fn test() { + let reference = Box::new(MapAccum {ite : 1, f : 2, b : Some(3)}); + let mut a = *reference; + +} + +pub trait SuperIterator : Iterator + Sized { + // fn map_accum(self, f : impl FnMut(Self::Item, &B) -> (C, B), b : B) -> Map C> where Self : Sized{ + // map_accum(f, b, self) + // } + + // fn map_accum2(self, f : impl FnMut(Self::Item, &B) -> (C, B), b : B) -> Map C> where Self : Sized{ + // let mut sf = StatefullFct { b, f }; + // let res = self.map(move |a| {sf.truc(a)}); + // return res; + // } + + // fn map_accum2(self, f : impl FnMut(Self::Item, &B) -> (C, B), b : B) -> impl Iterator { + // map_accum(f, b, self) + // } + + fn map_accum (C, B)>(self, b : B, f : F) -> MapAccum{ + //panic!(); + MapAccum { ite : self, f, b : Some(b) } + } + +} + +impl SuperIterator for T where T : Iterator {} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7c6f291 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,156 @@ +mod git; +mod ite; + +use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder, Error, HttpRequest}; +use askama_actix::Template; +use actix_session::{Session, CookieSession}; +use actix_web_httpauth::headers::authorization::{Authorization, Basic}; +use actix_web::http::header::Header; +use actix_web_httpauth::middleware::HttpAuthentication; +use actix_web::dev::ServiceRequest; +use actix_web_httpauth::extractors::basic::{BasicAuth, Config}; +use actix_web_httpauth::extractors::AuthenticationError; +use crate::git::{GitBrowseEntry, GitRepo, GitCommit, GitBrowseDir}; +use actix_web::middleware::Logger; +use env_logger::Env; +use crate::ite::SuperIterator; +use std::ops::Add; +use std::path::{PathBuf, Path}; + +#[derive(Template)] +#[template(path = "hello.html")] +struct HelloTemplate<'a> { + name: &'a str, +} + +#[derive(Template)] +#[template(path = "git.html")] +struct GitMainTemplate +where for <'a> &'a TS : IntoIterator, + for <'a> &'a ROOT : IntoIterator, +{ + user: String, + repo : String, + browse : TS, + root : ROOT, +} + +#[get("/")] +async fn hello() -> impl Responder { + HttpResponse::Ok().body("Bonjour monde !") +} + +#[get("/test")] +async fn hello_test() -> impl Responder { + HttpResponse::Ok().body("Coucou") +} + +#[get("/askama")] +async fn askama() -> impl Responder { + let name : &str = "world"; + HelloTemplate { name } +} + +#[get("/session")] +async fn hello_session(session : Session) -> impl Responder { + // session.renew(); + match session.set("VieuxVy", 1) { + Ok(_) => HttpResponse::Ok().body("Coucou\r\n"), + Err(e) => HttpResponse::BadGateway().body("fail\r\n"), + } + +} + +// #[get("/auth")] +async fn hello_auth(req : HttpRequest) -> impl Responder { + match Authorization::::parse(&req){ + Ok(auth) => HttpResponse::Ok().body(format!("Hello, {}!", auth.as_ref().user_id())), + Err(e) => HttpResponse::Unauthorized().body("forbidden") + } +} + +#[get("/git/{user}/{repo}/{commit}/{path:.*}")] +async fn git_main(web::Path((user, reponame, commitname, rootname)): web::Path<(String, String, String, String)>) -> impl Responder { + let repo = GitRepo::new(); + let path : Vec<(String, String)> = rootname.split("/").map_accum("/git/".to_string() + &user + "/" + &reponame + "/" + &commitname, |str_ref, b| { + let href = b + "/" + str_ref; + ((str_ref.to_string(), href.clone()), href) + }).collect(); + let commit = GitCommit::new(commitname); + let root = GitBrowseDir::new(rootname); + let browse = repo.browse(&commit, &root).await; + GitMainTemplate { user, repo : reponame, browse : browse, root : path} +} + +#[post("/echo")] +async fn echo(req_body: String) -> impl Responder { + HttpResponse::Ok().body(req_body) +} + +async fn manual_hello() -> impl Responder { + HttpResponse::Ok().body("Hey there!\r\n") +} + +#[get("/{id}/{name}/index.html")] +async fn index(web::Path((id, name)): web::Path<(u32, String)>) -> impl Responder { + format!("Hello {}! id:{}", name, id) +} + +async fn basic_auth_validator(req: ServiceRequest, credentials: BasicAuth) -> Result { + let config = req + .app_data::() + .map(|data| data.clone()) + .unwrap_or_else(Default::default); + match validate_credentials(credentials.user_id(), credentials.password().map(|s| s.trim())) { + Ok(res) => { + if res == true { + Ok(req) + } else { + Err(AuthenticationError::from(config).into()) + } + } + Err(_) => Err(AuthenticationError::from(config).into()), + } +} + +fn validate_credentials(user_id: &str, user_password: Option<&str>) -> Result +{ + if user_id.eq("karl") && user_password.eq(&Option::Some("password")) { + return Ok(true); + } + return Err(std::io::Error::new(std::io::ErrorKind::Other, "Authentication failed!")); +} + +#[actix_web::main] +async fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_web=info"); + env_logger::from_env(Env::default().default_filter_or("info")).init(); + HttpServer::new(|| { + let auth = HttpAuthentication::basic(basic_auth_validator); + App::new() + .wrap(Logger::default()) + // .wrap(Logger::new("%a %{User-Agent}i")) + .wrap(CookieSession::signed(&[0; 32]).secure(false)) + .service(hello) + .service(echo) + .service(hello_test) + .service(index) + .service(askama) + .service(git_main) + .service(hello_session) + // .service( + // web::scope("/auth") + // .wrap(auth) + // .route("/", web::get().to(hello_auth)) + // ) + .service( + web::resource("/auth") + .wrap(auth) + .route(web::get().to(hello_auth)) + ) + .route("/hey", web::get().to(manual_hello)) + }) + .bind("127.0.0.1:8080")? + .run() + .await +} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..5017baf --- /dev/null +++ b/templates/base.html @@ -0,0 +1,11 @@ + + + + + + {{repo}} + + +{% block content %}{% endblock %} + + \ No newline at end of file diff --git a/templates/git.html b/templates/git.html new file mode 100644 index 0000000..c9902e2 --- /dev/null +++ b/templates/git.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} + +{% block content %} + {% for (dir, prev) in root %}/{{dir}}{% endfor %} + +
    + {% for entry in browse %} +
  • {{ entry }}
  • + {% endfor %} +
+ +
+

+
+
+

{{user}}/{{repo}}

+
+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/hello.html b/templates/hello.html new file mode 100644 index 0000000..f04761e --- /dev/null +++ b/templates/hello.html @@ -0,0 +1,11 @@ + + + + + Title + +

Bonjour {{name}} ! Ceci est un paragraphe

+ + + + \ No newline at end of file