Looking at the code, you'll realize it's not fully functional ... dysfunctional.
To use the web server, include it in your code and register page handlers for the pages you need. Look at the UsingTheServer object to see how. It's pretty self-explanatory i hope. The pages map is populated with known pages, and when a page request is made, the web server tried to match the request against the pages map. If found, the partial function is executed.
You can use XML directly in Scala code, and this is where the server lies a bit. Instead of using HTML, we use XML that looks enough like HTML to fool the web browser. (OK, the browser won't be fooled, just tired from the lousy HTML quality nowadays...)
object WebServer {
var server: WebServerInstance = null
def main(args: Array[String]) {
if (args.length == 1) {
server = new WebServerInstance(args(0).toInt)
} else {
server = new WebServerInstance()
}
server.pages += ("/index.html" -> ((method: String, path: String, query:String) =>
<p>Welcome to { path }. I see you are trying to {method}. The answer is {path + query.reverse}</p>
))
server.pages += ("/" -> ((method: String, path: String, query:String) =>
server.pages("/index.html").tupled(method, path, query)))
server.start()
}
class WebServerInstance(val port: Int=8080) extends Thread {
import java.net.{Socket, ServerSocket}
import actors.Actor
import java.io.BufferedInputStream
import collection.mutable.HashMap
val server = new ServerSocket(port, 100)
val renderPoolSize = 5
var renderers = List[PageRenderer]()
for (i <- 1 to renderPoolSize) renderers = new PageRenderer :: renderers
renderers.foreach(p => p.start())
var pages = HashMap("default" -> ((method: String, path: String, query:String) =>
<p>Welcome to { path }. I see you are trying to {method}. Your question is {query}</p>
))
override def run() {
var i = 0
while (true) {
try {
val connection: Socket = server.accept
renderers(i) ! (i, connection)
i = (i+1)%renderPoolSize
} catch {
case ex: Exception => ex.printStackTrace()
}
}
}
class PageRenderer extends Actor {
def act() {
loop {
react {
case (id: Int, connection: Socket) =>
try {
val in = new BufferedInputStream(connection.getInputStream)
var c: Int = 0
var request = new StringBuilder()
do {
c = in.read()
if (c != -1) request.append(c.toChar)
} while ( in.available() > 0)
println(request)
val method = request.substring(0, request.indexOf(" "))
val url = request.substring(method.length() + 1, request.indexOf(" ", method.length()+2))
val path = if (url.contains("?")) url.substring(0, url.indexOf("?")) else url
val query = if (url.contains("?")) url.substring(url.indexOf("?") + 1) else ""
val out = connection.getOutputStream
val html = if (pages.contains(path)) pages(path).tupled(method, path, query)
else pages("default").tupled(method, path, query)
val response = new StringBuilder("HTTP/1.0 200 OK\r\n" +
"Server: labserver\r\n" +
"Content-length: " + html.toString().length() + "\r\n" +
"Content-type: text/html\r\n" +
"\r\n" +
html
);
val binaryResponse: Array[Byte] = response.toArray.map(c => c.toByte)
out.write(binaryResponse)
in.close()
out.close()
connection.close()
} catch {
case ex: Exception => ex.printStackTrace()
}
}
}
}
}
}
}
object UsingTheServer {
def main(args: Array[String]) {
WebServer.main(Array("8080"))
MyStuff.getClass
}
object MyStuff {
var events = List[String]()
WebServer.server.pages += ("/addStuff" -> ((method: String, path: String, query:String) =>
<form action="/doAddStuff" method="GET">
<p>Submit your title.</p>
<input name="title" type="text"/>
<input type="submit"/>
</form>
))
WebServer.server.pages += ("/doAddStuff" -> ((method: String, path: String, query:String) => {
events = events ++ (query :: Nil)
events.foreach(println)
WebServer.server.pages("/addStuff").tupled(method, path, query)
}))
}
}
No comments:
Post a Comment