Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

136 lines (115 sloc) 3.629 kb
package rev
import (
"code.google.com/p/go.net/websocket"
"fmt"
"net/http"
"net/url"
"path"
"reflect"
"time"
)
var (
MainRouter *Router
MainTemplateLoader *TemplateLoader
MainWatcher *Watcher
websocketType = reflect.TypeOf((*websocket.Conn)(nil))
)
// This method handles all requests. It dispatches to handleInternal after
// handling / adapting websocket connections.
func handle(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Upgrade") == "websocket" {
websocket.Handler(func(ws *websocket.Conn) {
r.Method = "WS"
handleInternal(w, r, ws)
}).ServeHTTP(w, r)
} else {
handleInternal(w, r, nil)
}
}
func handleInternal(w http.ResponseWriter, r *http.Request, ws *websocket.Conn) {
// TODO: StaticPathsCache
req, resp := NewRequest(r), NewResponse(w)
if MainWatcher != nil {
err := MainWatcher.Notify()
if err != nil {
RenderError(req, resp, err)
return
}
}
// Figure out the Controller/Action
var route *RouteMatch = MainRouter.Route(r)
if route == nil {
NotFound(req, resp, "No matching route found")
return
}
// The route may want to explicitly return a 404.
if route.Action == "404" {
NotFound(req, resp, "(intentionally)")
return
}
// Dispatch the static files first.
if route.StaticFilename != "" {
http.ServeFile(w, r, route.StaticFilename)
return
}
// Construct the controller and get the method to call.
controller, appControllerPtr := NewAppController(req, resp, route.ControllerName, route.MethodName)
if controller == nil {
NotFound(req, resp, fmt.Sprintln("No matching action found:", route.Action))
return
}
var method reflect.Value = appControllerPtr.MethodByName(controller.MethodType.Name)
if !method.IsValid() {
WARN.Printf("Function %s not found on Controller %s",
route.MethodName, route.ControllerName)
NotFound(req, resp, fmt.Sprintln("No matching action found:", route.Action))
return
}
// Add the route Params to the Request Params.
for key, value := range route.Params {
url.Values(controller.Params.Values).Add(key, value)
}
// Collect the values for the method's arguments.
var actualArgs []reflect.Value
for _, arg := range controller.MethodType.Args {
// If they accept a websocket connection, treat that arg specially.
var boundArg reflect.Value
if arg.Type == websocketType {
boundArg = reflect.ValueOf(ws)
} else {
boundArg = controller.Params.Bind(arg.Name, arg.Type)
}
actualArgs = append(actualArgs, boundArg)
}
// Invoke the method.
// (Note that the method Value is already bound to the appController receiver.)
controller.Invoke(appControllerPtr, method, actualArgs)
}
// Run the server.
// This is called from the generated main file.
func Run(address string, port int) {
routePath := path.Join(BasePath, "conf", "routes")
MainRouter = NewRouter(routePath)
MainTemplateLoader = NewTemplateLoader(ViewsPath, RevelTemplatePath)
// If DEV mode, create a watcher for templates and routes.
// The watcher calls Refresh() on things on the first request.
if RunMode == DEV {
MainWatcher = NewWatcher()
MainWatcher.Listen(MainTemplateLoader, ViewsPath, RevelTemplatePath)
MainWatcher.Listen(MainRouter, routePath)
} else {
// Else, call refresh on them directly.
MainTemplateLoader.Refresh()
MainRouter.Refresh()
}
server := &http.Server{
Addr: fmt.Sprintf("%s:%d", address, port),
Handler: http.HandlerFunc(handle),
}
plugins.OnAppStart()
go func() {
time.Sleep(100 * time.Millisecond)
fmt.Printf("Listening on port %d...\n", port)
}()
ERROR.Fatalln("Failed to listen:", server.ListenAndServe())
}
Jump to Line
Something went wrong with that request. Please try again.