mirror of https://github.com/ethereum/go-ethereum
parent
ab6ede51d7
commit
3af211dd65
@ -0,0 +1,122 @@ |
|||||||
|
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{}, seed int) { |
||||||
|
msg := &Message{Seed: seed, Data: data} |
||||||
|
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() { |
||||||
|
logger.Debugln("Listening write to client") |
||||||
|
for { |
||||||
|
select { |
||||||
|
|
||||||
|
// send message to the client
|
||||||
|
case msg := <-c.ch: |
||||||
|
logger.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() { |
||||||
|
logger.Debugln("Listening read from client") |
||||||
|
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 { |
||||||
|
logger.Debugln(&msg) |
||||||
|
if c.onMessage != nil { |
||||||
|
c.onMessage(c, &msg) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
package websocket |
||||||
|
|
||||||
|
import "github.com/ethereum/eth-go/ethutil" |
||||||
|
|
||||||
|
type Message struct { |
||||||
|
Call string `json:"call"` |
||||||
|
Args []interface{} `json:"args"` |
||||||
|
Seed int `json:"seed"` |
||||||
|
Data interface{} `json:"data"` |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Message) Arguments() *ethutil.Value { |
||||||
|
return ethutil.NewValue(self.Args) |
||||||
|
} |
@ -0,0 +1,127 @@ |
|||||||
|
package websocket |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
|
||||||
|
"github.com/ethereum/eth-go/ethlog" |
||||||
|
|
||||||
|
ws "code.google.com/p/go.net/websocket" |
||||||
|
) |
||||||
|
|
||||||
|
var logger = ethlog.NewLogger("WS") |
||||||
|
|
||||||
|
// Chat server.
|
||||||
|
type Server struct { |
||||||
|
httpServ string |
||||||
|
pattern string |
||||||
|
messages []*Message |
||||||
|
clients map[int]*Client |
||||||
|
addCh chan *Client |
||||||
|
delCh chan *Client |
||||||
|
sendAllCh chan string |
||||||
|
doneCh chan bool |
||||||
|
errCh chan error |
||||||
|
msgFunc MsgFunc |
||||||
|
} |
||||||
|
|
||||||
|
// Create new chat server.
|
||||||
|
func NewServer(pattern, httpServ string) *Server { |
||||||
|
clients := make(map[int]*Client) |
||||||
|
addCh := make(chan *Client) |
||||||
|
delCh := make(chan *Client) |
||||||
|
sendAllCh := make(chan string) |
||||||
|
doneCh := make(chan bool) |
||||||
|
errCh := make(chan error) |
||||||
|
|
||||||
|
return &Server{ |
||||||
|
httpServ, |
||||||
|
pattern, |
||||||
|
nil, |
||||||
|
clients, |
||||||
|
addCh, |
||||||
|
delCh, |
||||||
|
sendAllCh, |
||||||
|
doneCh, |
||||||
|
errCh, |
||||||
|
nil, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Server) Add(c *Client) { |
||||||
|
s.addCh <- c |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Server) Del(c *Client) { |
||||||
|
s.delCh <- c |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Server) SendAll(msg string) { |
||||||
|
s.sendAllCh <- msg |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Server) Done() { |
||||||
|
s.doneCh <- true |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Server) Err(err error) { |
||||||
|
s.errCh <- err |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Server) servHTTP() { |
||||||
|
logger.Debugln("Serving http", s.httpServ) |
||||||
|
err := http.ListenAndServe(s.httpServ, nil) |
||||||
|
|
||||||
|
logger.Warnln(err) |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Server) MessageFunc(f MsgFunc) { |
||||||
|
s.msgFunc = f |
||||||
|
} |
||||||
|
|
||||||
|
// Listen and serve.
|
||||||
|
// It serves client connection and broadcast request.
|
||||||
|
func (s *Server) Listen() { |
||||||
|
logger.Debugln("Listening server...") |
||||||
|
|
||||||
|
// ws handler
|
||||||
|
onConnected := func(ws *ws.Conn) { |
||||||
|
defer func() { |
||||||
|
err := ws.Close() |
||||||
|
if err != nil { |
||||||
|
s.errCh <- err |
||||||
|
} |
||||||
|
}() |
||||||
|
|
||||||
|
client := NewClient(ws, s) |
||||||
|
client.onMessage = s.msgFunc |
||||||
|
s.Add(client) |
||||||
|
client.Listen() |
||||||
|
} |
||||||
|
// Disable Origin check. Request don't need to come necessarily from origin.
|
||||||
|
http.HandleFunc(s.pattern, func(w http.ResponseWriter, req *http.Request) { |
||||||
|
s := ws.Server{Handler: ws.Handler(onConnected)} |
||||||
|
s.ServeHTTP(w, req) |
||||||
|
}) |
||||||
|
logger.Debugln("Created handler") |
||||||
|
|
||||||
|
go s.servHTTP() |
||||||
|
|
||||||
|
for { |
||||||
|
select { |
||||||
|
|
||||||
|
// Add new a client
|
||||||
|
case c := <-s.addCh: |
||||||
|
s.clients[c.id] = c |
||||||
|
|
||||||
|
// del a client
|
||||||
|
case c := <-s.delCh: |
||||||
|
delete(s.clients, c.id) |
||||||
|
|
||||||
|
case err := <-s.errCh: |
||||||
|
logger.Debugln("Error:", err.Error()) |
||||||
|
|
||||||
|
case <-s.doneCh: |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue