aboutsummaryrefslogtreecommitdiffstats
path: root/websocket/client.go
blob: 340a67aea4971efa0bc684811e1a6ab8cbb71d11 (plain) (blame)
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
package websocket

import (
    "fmt"
    "io"

    ws "code.google.com/p/go.net/websocket"
)

const channelBufSize = 100

var maxId int = 0

type MsgFunc func(c *Client, msg *Message)

// Chat client.
type Client struct {
    id     int
    ws     *ws.Conn
    server *Server
    ch     chan *Message
    doneCh chan bool

    onMessage MsgFunc
}

// Create new chat client.
func NewClient(ws *ws.Conn, server *Server) *Client {

    if ws == nil {
        panic("ws cannot be nil")
    }

    if server == nil {
        panic("server cannot be nil")
    }

    maxId++
    ch := make(chan *Message, channelBufSize)
    doneCh := make(chan bool)

    return &Client{maxId, ws, server, ch, doneCh, nil}
}

func (c *Client) Id() int {
    return c.id
}

func (c *Client) Conn() *ws.Conn {
    return c.ws
}

func (c *Client) Write(data interface{}, id int) {
    c.write(&Message{Id: id, Data: data})
}
func (c *Client) Event(data interface{}, ev string, id int) {
    c.write(&Message{Id: id, Data: data, Event: ev})
}

func (c *Client) write(msg *Message) {
    select {
    case c.ch <- msg:
    default:
        c.server.Del(c)
        err := fmt.Errorf("client %d is disconnected.", c.id)
        c.server.Err(err)
    }
}

func (c *Client) Done() {
    c.doneCh <- true
}

// Listen Write and Read request via chanel
func (c *Client) Listen() {
    go c.listenWrite()
    c.listenRead()
}

// Listen write request via chanel
func (c *Client) listenWrite() {
    for {
        select {

        // send message to the client
        case msg := <-c.ch:
            wslogger.Debugln("Send:", msg)
            ws.JSON.Send(c.ws, msg)

        // receive done request
        case <-c.doneCh:
            c.server.Del(c)
            c.doneCh <- true // for listenRead method
            return
        }
    }
}

// Listen read request via chanel
func (c *Client) listenRead() {
    for {
        select {

        // receive done request
        case <-c.doneCh:
            c.server.Del(c)
            c.doneCh <- true // for listenWrite method
            return

        // read data from ws connection
        default:
            var msg Message
            err := ws.JSON.Receive(c.ws, &msg)
            if err == io.EOF {
                c.doneCh <- true
            } else if err != nil {
                c.server.Err(err)
            } else {
                wslogger.Debugln(&msg)
                if c.onMessage != nil {
                    c.onMessage(c, &msg)
                }
            }
        }
    }
}