architecture changes
This commit is contained in:
parent
d5d2233896
commit
769affa1b6
5 changed files with 103 additions and 92 deletions
|
@ -8,3 +8,6 @@ Why "Sheldon Director"?
|
||||||
|
|
||||||
Because it is the real name of that villain in _Kim Possible_ who went by the
|
Because it is the real name of that villain in _Kim Possible_ who went by the
|
||||||
pseudonym "Gemini". (https://kimpossible.fandom.com/wiki/Gemini)
|
pseudonym "Gemini". (https://kimpossible.fandom.com/wiki/Gemini)
|
||||||
|
|
||||||
|
Though you are free to imagine the shortened name stands for Sheldon Daemon.
|
||||||
|
But in that case you'll have to come up with your own explanation.
|
||||||
|
|
47
src/main.rs
47
src/main.rs
|
@ -1,49 +1,6 @@
|
||||||
use std::net::{TcpListener, TcpStream, SocketAddr};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::thread;
|
|
||||||
use openssl::ssl::{SslMethod, SslAcceptor, SslStream, SslFiletype};
|
|
||||||
use url::Url;
|
|
||||||
mod server;
|
mod server;
|
||||||
|
|
||||||
fn build_acceptor() -> std::sync::Arc<SslAcceptor> {
|
|
||||||
let mut acceptor = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls()).unwrap();
|
|
||||||
acceptor.set_private_key_file("doc/key.pem", SslFiletype::PEM).unwrap();
|
|
||||||
acceptor.set_certificate_chain_file("doc/cert.pem").unwrap();
|
|
||||||
acceptor.check_private_key().unwrap();
|
|
||||||
return Arc::new(acceptor.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_server() {
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_client(mut stream: SslStream<TcpStream>) {
|
|
||||||
let mut buffer = [0; 1026];
|
|
||||||
stream.ssl_read(&mut buffer);
|
|
||||||
let request = String::from_utf8(buffer.to_vec()).unwrap();
|
|
||||||
let url = Url::parse(&request).unwrap();
|
|
||||||
|
|
||||||
let data = server::handle(&url);
|
|
||||||
|
|
||||||
stream.ssl_write(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let addrs = [
|
let server = server::Server::new("gemini://localhost");
|
||||||
SocketAddr::from(([127, 0, 0, 1], 1965)),
|
server.serve();
|
||||||
];
|
|
||||||
let acceptor = build_acceptor();
|
|
||||||
let listener = TcpListener::bind(&addrs[..]).unwrap();
|
|
||||||
|
|
||||||
for stream in listener.incoming() {
|
|
||||||
match stream {
|
|
||||||
Ok(stream) => {
|
|
||||||
let acceptor = acceptor.clone();
|
|
||||||
thread::spawn(move || {
|
|
||||||
let stream = acceptor.accept(stream).unwrap();
|
|
||||||
handle_client(stream);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Err(e) => { /* connection failed */ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,7 @@
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use crate::server::response::{Status, Header, Response};
|
use crate::server::response;
|
||||||
|
use crate::server::ServerConfig;
|
||||||
|
|
||||||
pub trait Handler {
|
pub fn handle(config: &ServerConfig, url: Url) -> Option<response::Response> {
|
||||||
fn handle(&self, url : Url) -> Option<Response>;
|
Some(response::invalid_protocol())
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TestHandler {
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Handler for TestHandler {
|
|
||||||
fn handle(&self, url : Url) -> Option<Response> {
|
|
||||||
let header = Header::new(Status::Success, "text/gemini");
|
|
||||||
return Some(Response::new(header, Vec::new()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,79 @@
|
||||||
use std::vec::Vec;
|
use crate::server::response::Response;
|
||||||
|
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod, SslStream};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::net::{SocketAddr, TcpListener, TcpStream};
|
||||||
|
use std::thread;
|
||||||
|
use std::vec::Vec;
|
||||||
|
use std::sync::Arc;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
mod handler;
|
pub mod response;
|
||||||
mod response;
|
pub mod handler;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ServerConfig {
|
||||||
|
defaultHost: Url,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
handlers: Vec<Box<dyn handler::Handler>>,
|
acceptor: std::sync::Arc<SslAcceptor>,
|
||||||
|
config: ServerConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
pub fn new() -> Server {
|
pub fn new(host: &str) -> Server {
|
||||||
Server{handlers: Vec::<Box<dyn handler::Handler>>::new()}
|
let config = ServerConfig{defaultHost: Url::parse(host).unwrap()};
|
||||||
|
|
||||||
|
Server {
|
||||||
|
acceptor: build_acceptor(),
|
||||||
|
config: config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serve(&self) {
|
||||||
|
let addrs = [SocketAddr::from(([127, 0, 0, 1], 1965))];
|
||||||
|
let listener = TcpListener::bind(&addrs[..]).unwrap();
|
||||||
|
|
||||||
|
for stream in listener.incoming() {
|
||||||
|
match stream {
|
||||||
|
Ok(stream) => {
|
||||||
|
let acceptor = self.acceptor.clone();
|
||||||
|
let config = self.config.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let stream = acceptor.accept(stream).unwrap();
|
||||||
|
handle_client(&config, stream);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(e) => { /* connection failed */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register(host: &str, server: Server) {
|
fn handle_client(config: &ServerConfig, mut stream: SslStream<TcpStream>) {
|
||||||
//// servers.insert(
|
let mut buffer = [0; 1026];
|
||||||
//// host.to_string(),
|
stream.ssl_read(&mut buffer);
|
||||||
//// server,
|
let request = String::from_utf8(buffer.to_vec()).unwrap();
|
||||||
//// );
|
|
||||||
|
let location = match Url::parse(&request) {
|
||||||
|
Ok(url) => url,
|
||||||
|
Err(e) => config.defaultHost.join(&request).unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let response = match handler::handle(config, location) {
|
||||||
|
Some(response) => response,
|
||||||
|
None => response::internal_error(),
|
||||||
|
};
|
||||||
|
|
||||||
|
stream.ssl_write(&response.format());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle(url: &Url) -> Vec<u8> {
|
fn build_acceptor() -> std::sync::Arc<SslAcceptor> {
|
||||||
return Vec::new();
|
let mut acceptor = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls()).unwrap();
|
||||||
|
acceptor
|
||||||
|
.set_private_key_file("doc/key.pem", SslFiletype::PEM)
|
||||||
|
.unwrap();
|
||||||
|
acceptor.set_certificate_chain_file("doc/cert.pem").unwrap();
|
||||||
|
acceptor.check_private_key().unwrap();
|
||||||
|
return Arc::new(acceptor.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
//static mut servers : HashMap<String, Server> = HashMap::new();
|
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,12 @@ use std::vec::Vec;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
Input = 1,
|
Input = 10,
|
||||||
Success = 2,
|
Success = 20,
|
||||||
Redirect = 3,
|
Redirect = 30,
|
||||||
TemporaryFailure = 4,
|
TemporaryFailure = 40,
|
||||||
PermanentFailure = 5,
|
PermanentFailure = 50,
|
||||||
ClientCertificateRequired = 6,
|
ClientCertificateRequired = 60,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Header {
|
pub struct Header {
|
||||||
|
@ -22,28 +22,27 @@ pub struct Response {
|
||||||
|
|
||||||
impl Header {
|
impl Header {
|
||||||
pub fn new(status: Status, meta: &str) -> Header {
|
pub fn new(status: Status, meta: &str) -> Header {
|
||||||
Header{
|
Header {
|
||||||
status: status,
|
status: status,
|
||||||
meta: meta.to_string(),
|
meta: meta.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format(&self) -> String {
|
pub fn format(&self) -> String {
|
||||||
let status: u8 = self.status as u8;
|
format!("{} {}\r\n", self.status as u8, self.meta)
|
||||||
return format!("{} {}\r\n", status * 10, self.meta)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
pub fn new(header: Header, data: Vec<u8>) -> Response {
|
pub fn new(header: Header, data: Vec<u8>) -> Response {
|
||||||
Response{
|
Response {
|
||||||
header: header,
|
header: header,
|
||||||
data: data,
|
data: data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_empty(header: Header) -> Response {
|
pub fn new_empty(header: Header) -> Response {
|
||||||
Response{
|
Response {
|
||||||
header: header,
|
header: header,
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
}
|
}
|
||||||
|
@ -56,11 +55,23 @@ impl Response {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invalid_protocol () -> Response {
|
pub fn invalid_protocol() -> Response {
|
||||||
Response::new_empty(
|
Response::new_empty(Header::new(
|
||||||
Header::new(
|
|
||||||
Status::PermanentFailure,
|
Status::PermanentFailure,
|
||||||
"this protocol is not supported"
|
"this protocol is not supported",
|
||||||
),
|
))
|
||||||
)
|
}
|
||||||
|
|
||||||
|
pub fn not_understood() -> Response {
|
||||||
|
Response::new_empty(Header::new(
|
||||||
|
Status::PermanentFailure,
|
||||||
|
"request not understood",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn internal_error() -> Response {
|
||||||
|
Response::new_empty(Header::new(
|
||||||
|
Status::PermanentFailure,
|
||||||
|
"internal server error",
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue