-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapplication.rs
221 lines (195 loc) · 8.62 KB
/
application.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#![crate_id = "application"]
#![crate_type="lib"]
//! The main WD-42 application.
//!
//! The majority of the interface that you as a user will see is exposed
//! via this Application module and includes activities such as
//! registering request handlers, applying middleware functions, and setting
//! configuration variables.
#![feature(globs)]
extern crate collections;
extern crate http;
extern crate time;
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::{Writer, File};
use std::path::Path;
use std::{fmt, Vec, os};
use http::server::{Config, Server, Request, ResponseWriter};
use http::server::request::{Star, AbsoluteUri, AbsolutePath, Authority};
use http::status::{BadRequest, MethodNotAllowed, Ok, InternalServerError};
use http::method::{Get, Head, Post, Put, Delete, Trace, Options, Connect, Patch};
use http::headers::content_type::MediaType;
use collections::HashMap;
// The basic Rust App to be exposed
/// The Application struct. The meat of the WD-42 Framework
#[deriving(Clone)]
pub struct App {
/// The root directory for your static files including html, css, and js files.
viewDirectory: Path,
/// The data structure to hold your get routes and get request handlers.
/// Users should not interact with this directly and should use App::get() instead.
getRoutes: ~HashMap<~str, fn(&http::server::request::Request, &mut http::server::response::ResponseWriter<>)>,
/// The data structure to hold your put routes and put request handlers.
/// Users should not interact with this directly and should use App::put() instead.
putRoutes: ~HashMap<~str, fn(&http::server::request::Request, &mut http::server::response::ResponseWriter<>)>,
/// The data structure to hold your post routes and post request handlers.
/// Users should not interact with this directly and should use App::post() instead.
postRoutes: ~HashMap<~str, fn(&http::server::request::Request, &mut http::server::response::ResponseWriter<>)>,
/// The data structure to hold your del routes and del request handlers.
/// Users should not interact with this directly and should use App::del() instead.
delRoutes: ~HashMap<~str, fn(&http::server::request::Request, &mut http::server::response::ResponseWriter<>)>,
/// The data structure to hold the applied middleware functions. Add a function to this list using App::apply()
middlewareStack: ~Vec<fn(&mut http::server::request::Request)>,
/// The port that your server will be listening on
port: u16
}
impl App {
/// Create a new Application.
pub fn new() -> App {
App {
viewDirectory: os::getcwd(),
getRoutes: ~HashMap::new(),
postRoutes: ~HashMap::new(),
delRoutes: ~HashMap::new(),
putRoutes: ~HashMap::new(),
middlewareStack: ~Vec::new(),
port: 8000
}
}
/// Set the port to be listened on
pub fn setPort(&mut self, new_port: u16) {
self.port = new_port
}
/// Supply a port to listen on and actually start the WD-42 server.
pub fn listen(&mut self, port : u16) {
self.setPort(port);
let s = self.clone();
s.serve_forever();
}
/// Add a middleware function to the middleware stack to be run on the
/// Request objects before reaching your request handlers.
///
/// This is often an ideal place to put authentication logic as well as
/// light analytics tracking.
pub fn apply(&mut self, f : fn(&mut http::server::request::Request)) {
self.middlewareStack.push(f);
}
/// Set the root public directory where you will place your html, css, and js files
pub fn set_public_dir(&mut self, path_to_dir: &str) {
self.viewDirectory.push(Path::new(path_to_dir));
println!("Setting public directory to: {}", self.viewDirectory.display());
}
/// Add a GET route and GET request handler for that route to the application.
/// app.get("/", indexGet) will register the indexGet function to be called whenever
/// the server sees a get request to the route "/"
pub fn get(&mut self, route : ~str, f : fn(&http::server::request::Request, &mut http::server::response::ResponseWriter<>)) {
self.getRoutes.insert(route, f);
}
/// The same as app.get() except for post requests
pub fn post(&mut self, route : ~str, f : fn(&http::server::request::Request, &mut http::server::response::ResponseWriter<>)) {
self.postRoutes.insert(route, f);
}
/// The same as app.get() except for put requests
pub fn put(&mut self, route : ~str, f : fn(&http::server::request::Request, &mut http::server::response::ResponseWriter<>)) {
self.putRoutes.insert(route, f);
}
/// The same as app.get() except for del requests
pub fn del(&mut self, route : ~str, f : fn(&http::server::request::Request, &mut http::server::response::ResponseWriter<>)) {
self.delRoutes.insert(route, f);
}
}
impl Server for App {
fn get_config(&self) -> Config {
Config { bind_address: SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: self.port }, viewDirectory: self.viewDirectory.clone()}
}
fn handle_request(&self, r: &mut Request, w: &mut ResponseWriter) {
w.headers.date = Some(time::now_utc());
w.headers.server = Some(~"WD-42 Server");
for mw in self.middlewareStack.iter() {
(*mw)(r);
}
let uri = r.request_uri.clone();
match (&r.method, uri) {
(&Get, AbsolutePath(p)) => {
println!("\nGET request to path: {}", p);
// let s = self.clone();
if self.getRoutes.contains_key(&p) {
let v = self.getRoutes.get(&p);
// let f = v.get;
(*v)(r, w);
} else {
let path : Path = self.viewDirectory.clone().join(Path::new(p.slice_from(1)));
if path.exists() {
let path = p.clone();
w.sendFile(path.slice_from(1).to_owned());
} else {
w.status = MethodNotAllowed;
w.write(bytes!("Page not found"));
}
}
},
(&Post, AbsolutePath(p)) => {
if self.postRoutes.contains_key(&p) {
println!("\nPOST request to path");
let v = self.postRoutes.get(&p);
// let f = v.get;
(*v)(r, w);
} else {
w.status = MethodNotAllowed;
w.write(bytes!("Page not found"));
}
},
(&Put, AbsolutePath(p)) => {
if self.putRoutes.contains_key(&p) {
println!("\nPUT request to path");
let v = self.putRoutes.get(&p);
// let f = v.get;
(*v)(r, w);
} else {
w.status = MethodNotAllowed;
w.write(bytes!("Page not found"));
}
},
(&Delete, AbsolutePath(p)) => {
if self.delRoutes.contains_key(&p) {
println!("\nDELETE request to path");
let v = self.delRoutes.get(&p);
// let f = v.get;
(*v)(r, w);
} else {
w.status = MethodNotAllowed;
w.write(bytes!("Page not found"));
}
},
(_, _) => {
println!("Could not match with a predefined request handler");
}
}
}
}
// So we can println!("{}", myApp)
impl fmt::Show for App {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut printstr: ~str = format!("Rustic app running on port: {}", self.port);
printstr = printstr + "\n=================================\n\tRoutes defined for:\n=================================\nGET:";
for (route, func) in self.getRoutes.iter() {
printstr = printstr + format!("\n | {}", route);
}
printstr = printstr + "\n\nPOST:";
for (route, func) in self.postRoutes.iter() {
printstr = printstr + format!("\n | {}", route);
}
printstr = printstr + "\n\nPUT:";
for (route, func) in self.putRoutes.iter() {
printstr = printstr + format!("\n | {}", route);
}
printstr = printstr + "\n\nDELETE:";
for (route, func) in self.delRoutes.iter() {
printstr = printstr + format!("\n | {}", route);
}
write!(f.buf, "{}", printstr)
}
}
fn main() {
println!("Yay compilation");
}