Skip to content

Commit 7c6055d

Browse files
committed
Refactor server
- move handlers into separate files - use interfaces for handlers, etc - update README.md files
1 parent 14a5bc3 commit 7c6055d

File tree

9 files changed

+202
-128
lines changed

9 files changed

+202
-128
lines changed

README.md

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,3 @@
11
# Go DDP
22

33
DDP server and client implemented with go.
4-
5-
## Server Example
6-
7-
```go
8-
package main
9-
10-
import (
11-
"github.com/meteorhacks/goddp"
12-
)
13-
14-
func main() {
15-
server := goddp.NewServer()
16-
server.Method("hello", methodHandler)
17-
server.Listen(":1337")
18-
}
19-
20-
func methodHandler(p []interface{}) (interface{}, error) {
21-
return "result", nil
22-
}
23-
```

goddp.go

Lines changed: 0 additions & 14 deletions
This file was deleted.

server/README.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,20 @@ import (
1212
)
1313

1414
func main() {
15-
server := server.New()
16-
server.Method("hello", methodHandler)
17-
server.Listen(":1337")
15+
s := server.New()
16+
s.Method("double", handler)
17+
s.Listen(":1337")
1818
}
1919

20-
func methodHandler(p []interface{}) (interface{}, error) {
21-
return "result", nil
20+
func handler(ctx server.MethodContext) {
21+
n, ok := ctx.Args[0].(float64)
22+
23+
if !ok {
24+
ctx.SendError("invalid parameters")
25+
} else {
26+
ctx.SendResult(n * 2)
27+
}
28+
29+
ctx.SendUpdated()
2230
}
2331
```

server/handler_connect.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package server
2+
3+
import (
4+
"github.com/meteorhacks/goddp/utils/random"
5+
)
6+
7+
type ConnectHandler struct {
8+
server Server
9+
}
10+
11+
func NewConnectHandler(s Server) Handler {
12+
return &ConnectHandler{s}
13+
}
14+
15+
func (h *ConnectHandler) handle(res Response, m Message) error {
16+
return res.WriteJSON(map[string]string{
17+
"msg": "connected",
18+
"session": random.Id(17),
19+
})
20+
}

server/handler_method.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package server
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
)
7+
8+
type MethodHandler struct {
9+
server Server
10+
}
11+
12+
func NewMethodHandler(s Server) Handler {
13+
return &MethodHandler{s}
14+
}
15+
16+
func (h *MethodHandler) handle(res Response, m Message) error {
17+
fn, ok := h.server.methods[m.Method]
18+
19+
if !ok {
20+
err := errors.New(fmt.Sprintf("method %s not found", m.Method))
21+
return err
22+
}
23+
24+
ctx := NewMethodContext(m, res)
25+
fn(ctx)
26+
27+
return nil
28+
}

server/handler_ping.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package server
2+
3+
type PingHandler struct {
4+
server Server
5+
}
6+
7+
func NewPingHandler(s Server) Handler {
8+
return &PingHandler{s}
9+
}
10+
11+
func (h *PingHandler) handle(res Response, m Message) error {
12+
if m.ID != "" {
13+
return h.withId(res, m)
14+
} else {
15+
return h.withoutId(res, m)
16+
}
17+
}
18+
19+
func (p *PingHandler) withId(res Response, m Message) error {
20+
return res.WriteJSON(map[string]string{
21+
"msg": "pong",
22+
"id": m.ID,
23+
})
24+
}
25+
26+
func (p *PingHandler) withoutId(res Response, m Message) error {
27+
return res.WriteJSON(map[string]string{
28+
"msg": "pong",
29+
})
30+
}

server/method_context.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package server
2+
3+
import (
4+
"errors"
5+
)
6+
7+
type MethodContext struct {
8+
ID string
9+
Args []interface{}
10+
Res Response
11+
Done bool
12+
Updated bool
13+
}
14+
15+
func NewMethodContext(m Message, res Response) MethodContext {
16+
ctx := MethodContext{}
17+
ctx.ID = m.ID
18+
ctx.Args = m.Params
19+
ctx.Res = res
20+
return ctx
21+
}
22+
23+
func (ctx *MethodContext) SendResult(r interface{}) error {
24+
if ctx.Done {
25+
err := errors.New("already sent results for method")
26+
return err
27+
}
28+
29+
ctx.Done = true
30+
return ctx.Res.WriteJSON(map[string]interface{}{
31+
"msg": "result",
32+
"id": ctx.ID,
33+
"result": r,
34+
})
35+
}
36+
37+
func (ctx *MethodContext) SendError(e string) error {
38+
if ctx.Done {
39+
err := errors.New("already sent results for method")
40+
return err
41+
}
42+
43+
ctx.Done = true
44+
return ctx.Res.WriteJSON(map[string]interface{}{
45+
"msg": "result",
46+
"id": ctx.ID,
47+
"error": map[string]string{
48+
"error": e,
49+
},
50+
})
51+
}
52+
53+
func (ctx *MethodContext) SendUpdated() error {
54+
if ctx.Updated {
55+
err := errors.New("already sent updated for method")
56+
return err
57+
}
58+
59+
ctx.Updated = true
60+
return ctx.Res.WriteJSON(map[string]interface{}{
61+
"msg": "updated",
62+
"methods": []string{ctx.ID},
63+
})
64+
}

server/server.go

Lines changed: 33 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -3,138 +3,84 @@ package server
33
import (
44
"encoding/json"
55
"errors"
6-
"fmt"
76
"net/http"
87

98
"github.com/gorilla/websocket"
10-
"github.com/meteorhacks/goddp/utils/random"
119
)
1210

1311
type Server struct {
14-
methods map[string]MethodHandler
12+
handlers map[string]Handler
13+
methods map[string]MethodFn
1514
upgrader websocket.Upgrader
1615
}
1716

1817
func New() Server {
19-
server := Server{}
20-
server.methods = make(map[string]MethodHandler)
21-
server.upgrader = websocket.Upgrader{
18+
s := Server{}
19+
s.methods = make(map[string]MethodFn)
20+
s.upgrader = websocket.Upgrader{
2221
ReadBufferSize: 1024,
2322
WriteBufferSize: 1024,
2423
}
2524

26-
return server
27-
}
25+
s.handlers = map[string]Handler{
26+
"connect": NewConnectHandler(s),
27+
"ping": NewPingHandler(s),
28+
"method": NewMethodHandler(s),
29+
}
2830

29-
func (s *Server) Method(n string, h MethodHandler) {
30-
s.methods[n] = h
31+
return s
3132
}
3233

33-
func (s *Server) Listen(ipPort string) {
34+
func (s *Server) Listen(addr string) {
3435
http.HandleFunc("/websocket", s.Handler)
35-
http.ListenAndServe(ipPort, nil)
36+
http.ListenAndServe(addr, nil)
37+
}
38+
39+
func (s *Server) Method(name string, fn MethodFn) {
40+
s.methods[name] = fn
3641
}
3742

3843
func (s *Server) Handler(w http.ResponseWriter, r *http.Request) {
3944
ws, err := s.upgrader.Upgrade(w, r, nil)
40-
4145
if err != nil {
42-
fmt.Println("Error: could not creating websocket connection")
46+
// TODO => handle non-websocket requests
4347
return
4448
}
4549

4650
for {
47-
msg, err := readMessage(ws)
51+
msg, err := readMessage(req)
4852

4953
if err != nil {
50-
ws.Close()
5154
break
5255
}
5356

54-
switch {
55-
case msg.Msg == "ping":
56-
go s.handlePing(ws, msg)
57-
case msg.Msg == "connect":
58-
go s.handleConnect(ws, msg)
59-
case msg.Msg == "method":
60-
go s.handleMethod(ws, msg)
61-
default:
62-
fmt.Println("Error: unknown ddp message", *msg)
63-
ws.Close()
57+
if h, ok := s.handlers[msg.Msg]; ok {
58+
go h.handle(res, msg)
59+
} else {
60+
// TODO => send "error" ddp message
6461
break
6562
}
6663
}
67-
}
68-
69-
func (s *Server) handleConnect(c *websocket.Conn, m *Message) {
70-
err := c.WriteJSON(map[string]string{
71-
"msg": "connected",
72-
"session": random.Id(17),
73-
})
7464

75-
if err != nil {
76-
fmt.Println(err)
77-
}
65+
ws.Close()
7866
}
7967

80-
func (s *Server) handlePing(c *websocket.Conn, m *Message) {
81-
if m.Id != "" {
82-
err := c.WriteJSON(map[string]string{
83-
"msg": "pong",
84-
"id": m.Id,
85-
})
86-
87-
if err != nil {
88-
fmt.Println(err)
89-
}
90-
} else {
91-
err := c.WriteJSON(map[string]string{
92-
"msg": "pong",
93-
})
94-
95-
if err != nil {
96-
fmt.Println(err)
97-
}
98-
}
99-
}
100-
101-
func (s *Server) handleMethod(c *websocket.Conn, m *Message) {
102-
res, _ := s.methods[m.Method](m.Params)
103-
err := c.WriteJSON(map[string]interface{}{
104-
"msg": "result",
105-
"id": m.Id,
106-
"result": res,
107-
})
68+
func readMessage(req Request) (Message, error) {
69+
t, str, err := req.ReadMessage()
70+
msg := Message{}
10871

10972
if err != nil {
110-
fmt.Println(err)
73+
return msg, err
11174
}
11275

113-
err = c.WriteJSON(map[string]interface{}{
114-
"msg": "updated",
115-
"methods": []string{m.Id},
116-
})
117-
118-
if err != nil {
119-
fmt.Println(err)
120-
}
121-
}
122-
123-
func readMessage(ws *websocket.Conn) (*Message, error) {
124-
t, str, err := ws.ReadMessage()
125-
msg := &Message{}
126-
127-
if err != nil {
128-
// error reading message
129-
return nil, err
76+
if t != 1 {
77+
err = errors.New("DDP does not supports binary streams yet")
78+
return msg, err
13079
}
13180

132-
if t != 1 {
133-
// ignore binary data
134-
err = errors.New("Error: DDP does not supports binary streams yet.")
135-
return nil, err
81+
if err := json.Unmarshal(str, &msg); err != nil {
82+
return msg, err
13683
}
13784

138-
err = json.Unmarshal(str, msg)
13985
return msg, nil
14086
}

0 commit comments

Comments
 (0)