Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d240869

Browse files
committed
An initial http engine for the revel framework
1 parent f594750 commit d240869

File tree

6 files changed

+158
-63
lines changed

6 files changed

+158
-63
lines changed

fakeapp_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,6 @@ func startFakeBookingApp() {
106106
RenderArgNames: map[int][]string{},
107107
},
108108
})
109-
109+
InitServerEngine(9000, GO_NATIVE_SERVER_ENGINE)
110110
runStartupHooks()
111111
}

server-engine.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
2+
// Revel Framework source code and usage is governed by a MIT style
3+
// license that can be found in the LICENSE file.
4+
5+
package revel
6+
7+
import (
8+
"fmt"
9+
"net"
10+
"net/http"
11+
"time"
12+
13+
"golang.org/x/net/websocket"
14+
)
15+
16+
17+
type ServerEngine interface {
18+
// Initialize the server (non blocking)
19+
Init(init *EngineInit)
20+
// Starts the server. This will block until server is stopped
21+
Start()
22+
// Fires a new event to the server
23+
Event(event string, args interface{})
24+
// Returns the engine instance for specific calls
25+
Engine() interface{}
26+
// Returns the engine Name
27+
Name() string
28+
// Handle the request an response
29+
Handle(w http.ResponseWriter, r *http.Request)
30+
}
31+
type EngineInit struct {
32+
Address,
33+
Network string
34+
Port int
35+
Callback func(http.ResponseWriter, *http.Request, *websocket.Conn)
36+
}
37+
38+
// Register the GOHttpServer engine
39+
func init() {
40+
RegisterServerEngine(&GOHttpServer{})
41+
}
42+
type GOHttpServer struct {
43+
Server *http.Server
44+
ServerInit *EngineInit
45+
}
46+
47+
func (g *GOHttpServer) Init(init *EngineInit) {
48+
g.ServerInit = init
49+
g.Server = &http.Server{
50+
Addr: init.Address,
51+
Handler: http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request){
52+
g.Handle(writer,request)
53+
}),
54+
ReadTimeout: time.Duration(Config.IntDefault("http.timeout.read", 0)) * time.Second,
55+
WriteTimeout: time.Duration(Config.IntDefault("http.timeout.write", 0)) * time.Second,
56+
}
57+
// Server already initialized
58+
59+
60+
}
61+
func (g *GOHttpServer) Start() {
62+
go func() {
63+
time.Sleep(100 * time.Millisecond)
64+
fmt.Printf("Listening on %s...\n", g.Server.Addr)
65+
}()
66+
if HTTPSsl {
67+
if g.ServerInit.Network != "tcp" {
68+
// This limitation is just to reduce complexity, since it is standard
69+
// to terminate SSL upstream when using unix domain sockets.
70+
ERROR.Fatalln("SSL is only supported for TCP sockets. Specify a port to listen on.")
71+
}
72+
ERROR.Fatalln("Failed to listen:",
73+
g.Server.ListenAndServeTLS(HTTPSslCert, HTTPSslKey))
74+
} else {
75+
listener, err := net.Listen(g.ServerInit.Network, g.Server.Addr)
76+
if err != nil {
77+
ERROR.Fatalln("Failed to listen:", err)
78+
}
79+
ERROR.Fatalln("Failed to serve:", g.Server.Serve(listener))
80+
}
81+
82+
}
83+
84+
func (g *GOHttpServer) Handle(w http.ResponseWriter, r *http.Request) {
85+
if maxRequestSize := int64(Config.IntDefault("http.maxrequestsize", 0)); maxRequestSize > 0 {
86+
r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
87+
}
88+
89+
upgrade := r.Header.Get("Upgrade")
90+
if upgrade == "websocket" || upgrade == "Websocket" {
91+
websocket.Handler(func(ws *websocket.Conn) {
92+
//Override default Read/Write timeout with sane value for a web socket request
93+
if err := ws.SetDeadline(time.Now().Add(time.Hour * 24)); err != nil {
94+
ERROR.Println("SetDeadLine failed:", err)
95+
}
96+
r.Method = "WS"
97+
g.ServerInit.Callback(w, r, ws)
98+
}).ServeHTTP(w, r)
99+
} else {
100+
g.ServerInit.Callback(w, r, nil)
101+
}
102+
}
103+
104+
const GO_NATIVE_SERVER_ENGINE = "go"
105+
106+
func (g *GOHttpServer) Name() string {
107+
return GO_NATIVE_SERVER_ENGINE
108+
}
109+
110+
func (g *GOHttpServer) Engine() interface{} {
111+
return g.Server
112+
}
113+
114+
func (g *GOHttpServer) Event(event string, args interface{}) {
115+
116+
}

server.go

Lines changed: 27 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
package revel
66

77
import (
8-
"fmt"
98
"io"
10-
"net"
119
"net/http"
1210
"sort"
1311
"strconv"
@@ -22,29 +20,14 @@ var (
2220
MainRouter *Router
2321
MainTemplateLoader *TemplateLoader
2422
MainWatcher *Watcher
25-
Server *http.Server
23+
//Server *http.Server
24+
serverEngineMap = map[string]ServerEngine{}
25+
CurrentEngine ServerEngine
26+
ServerEngineInit *EngineInit
2627
)
2728

28-
// This method handles all requests. It dispatches to handleInternal after
29-
// handling / adapting websocket connections.
30-
func handle(w http.ResponseWriter, r *http.Request) {
31-
if maxRequestSize := int64(Config.IntDefault("http.maxrequestsize", 0)); maxRequestSize > 0 {
32-
r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
33-
}
34-
35-
upgrade := r.Header.Get("Upgrade")
36-
if upgrade == "websocket" || upgrade == "Websocket" {
37-
websocket.Handler(func(ws *websocket.Conn) {
38-
//Override default Read/Write timeout with sane value for a web socket request
39-
if err := ws.SetDeadline(time.Now().Add(time.Hour * 24)); err != nil {
40-
ERROR.Println("SetDeadLine failed:", err)
41-
}
42-
r.Method = "WS"
43-
handleInternal(w, r, ws)
44-
}).ServeHTTP(w, r)
45-
} else {
46-
handleInternal(w, r, nil)
47-
}
29+
func RegisterServerEngine(newEngine ServerEngine) {
30+
serverEngineMap[newEngine.Name()]=newEngine
4831
}
4932

5033
func handleInternal(w http.ResponseWriter, r *http.Request, ws *websocket.Conn) {
@@ -90,7 +73,7 @@ func handleInternal(w http.ResponseWriter, r *http.Request, ws *websocket.Conn)
9073
// It can be used as an alternative entry-point if one needs the http handler
9174
// to be exposed. E.g. to run on multiple addresses and ports or to set custom
9275
// TLS options.
93-
func InitServer() http.HandlerFunc {
76+
func InitServer() {
9477
runStartupHooks()
9578

9679
// Load templates
@@ -117,13 +100,20 @@ func InitServer() http.HandlerFunc {
117100
MainWatcher.Listen(MainTemplateLoader, MainTemplateLoader.paths...)
118101
}
119102

120-
return http.HandlerFunc(handle)
103+
// return http.HandlerFunc(handle)
121104
}
122105

123106
// Run the server.
124107
// This is called from the generated main file.
125108
// If port is non-zero, use that. Else, read the port from app.conf.
126109
func Run(port int) {
110+
111+
InitServerEngine(port, Config.StringDefault("server.engine",GO_NATIVE_SERVER_ENGINE))
112+
InitServer()
113+
CurrentEngine.Start()
114+
}
115+
116+
func InitServerEngine(port int, serverEngine string) {
127117
address := HTTPAddr
128118
if port == 0 {
129119
port = HTTPPort
@@ -143,35 +133,18 @@ func Run(port int) {
143133
localAddress = address + ":" + strconv.Itoa(port)
144134
}
145135

146-
Server = &http.Server{
147-
Addr: localAddress,
148-
Handler: http.HandlerFunc(handle),
149-
ReadTimeout: time.Duration(Config.IntDefault("http.timeout.read", 0)) * time.Second,
150-
WriteTimeout: time.Duration(Config.IntDefault("http.timeout.write", 0)) * time.Second,
151-
}
152-
153-
InitServer()
154-
155-
go func() {
156-
time.Sleep(100 * time.Millisecond)
157-
fmt.Printf("Listening on %s...\n", Server.Addr)
158-
}()
159-
160-
if HTTPSsl {
161-
if network != "tcp" {
162-
// This limitation is just to reduce complexity, since it is standard
163-
// to terminate SSL upstream when using unix domain sockets.
164-
ERROR.Fatalln("SSL is only supported for TCP sockets. Specify a port to listen on.")
165-
}
166-
ERROR.Fatalln("Failed to listen:",
167-
Server.ListenAndServeTLS(HTTPSslCert, HTTPSslKey))
168-
} else {
169-
listener, err := net.Listen(network, Server.Addr)
170-
if err != nil {
171-
ERROR.Fatalln("Failed to listen:", err)
172-
}
173-
ERROR.Fatalln("Failed to serve:", Server.Serve(listener))
174-
}
136+
var ok bool
137+
if CurrentEngine,ok = serverEngineMap[serverEngine];!ok {
138+
panic("Server Engine " + serverEngine +" Not found")
139+
} else {
140+
ServerEngineInit = &EngineInit{
141+
Address:localAddress,
142+
Network:network,
143+
Port:port,
144+
Callback:handleInternal,
145+
}
146+
CurrentEngine.Init(ServerEngineInit)
147+
}
175148
}
176149

177150
func runStartupHooks() {

server_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func benchmarkRequest(b *testing.B, req *http.Request) {
4848
b.ResetTimer()
4949
resp := httptest.NewRecorder()
5050
for i := 0; i < b.N; i++ {
51-
handle(resp, req)
51+
CurrentEngine.Handle(resp, req)
5252
}
5353
}
5454

@@ -59,29 +59,29 @@ func TestFakeServer(t *testing.T) {
5959
resp := httptest.NewRecorder()
6060

6161
// First, test that the expected responses are actually generated
62-
handle(resp, showRequest)
62+
CurrentEngine.Handle(resp, showRequest)
6363
if !strings.Contains(resp.Body.String(), "300 Main St.") {
6464
t.Errorf("Failed to find hotel address in action response:\n%s", resp.Body)
6565
t.FailNow()
6666
}
6767
resp.Body.Reset()
6868

69-
handle(resp, staticRequest)
69+
CurrentEngine.Handle(resp, staticRequest)
7070
sessvarsSize := getFileSize(t, filepath.Join(BasePath, "public", "js", "sessvars.js"))
7171
if int64(resp.Body.Len()) != sessvarsSize {
7272
t.Errorf("Expected sessvars.js to have %d bytes, got %d:\n%s", sessvarsSize, resp.Body.Len(), resp.Body)
7373
t.FailNow()
7474
}
7575
resp.Body.Reset()
7676

77-
handle(resp, jsonRequest)
77+
CurrentEngine.Handle(resp, jsonRequest)
7878
if !strings.Contains(resp.Body.String(), `"Address":"300 Main St."`) {
7979
t.Errorf("Failed to find hotel address in JSON response:\n%s", resp.Body)
8080
t.FailNow()
8181
}
8282
resp.Body.Reset()
8383

84-
handle(resp, plaintextRequest)
84+
CurrentEngine.Handle(resp, plaintextRequest)
8585
if resp.Body.String() != "Hello, World!" {
8686
t.Errorf("Failed to find greeting in plaintext response:\n%s", resp.Body)
8787
t.FailNow()

template.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,15 @@ type TemplateWatcher interface {
4444
}
4545

4646
type Template interface {
47+
// #Name: The name of the template.
4748
Name() string // Name of template
49+
// #Content: The content of the template as a string (Used in error handling).
4850
Content() []string // Content
51+
// #Render: Called by the server to render the template out the io.Writer, args contains the arguements to be passed to the template.
52+
// arg: wr io.Writer
53+
// arg: arg interface{}
4954
Render(wr io.Writer, arg interface{}) error
55+
// #Location: The full path to the file on the disk.
5056
Location() string // Disk location
5157
}
5258

testing/testsuite.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ func (t *TestSuite) NewTestRequest(req *http.Request) *TestRequest {
6969

7070
// Host returns the address and port of the server, e.g. "127.0.0.1:8557"
7171
func (t *TestSuite) Host() string {
72-
if revel.Server.Addr[0] == ':' {
73-
return "127.0.0.1" + revel.Server.Addr
72+
if revel.ServerEngineInit.Address[0] == ':' {
73+
return "127.0.0.1" + revel.ServerEngineInit.Address
7474
}
75-
return revel.Server.Addr
75+
return revel.ServerEngineInit.Address
7676
}
7777

7878
// BaseUrl returns the base http/https URL of the server, e.g. "http://127.0.0.1:8557".

0 commit comments

Comments
 (0)