Implemented WebSocket package
This commit is contained in:
parent
ab6ede51d7
commit
3af211dd65
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/ethereum/eth-go/ethchain"
|
"github.com/ethereum/eth-go/ethchain"
|
||||||
"github.com/ethereum/eth-go/ethlog"
|
"github.com/ethereum/eth-go/ethlog"
|
||||||
"github.com/ethereum/eth-go/ethutil"
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
"github.com/ethereum/eth-go/ethwire"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var poollogger = ethlog.NewLogger("BPOOL")
|
var poollogger = ethlog.NewLogger("BPOOL")
|
||||||
@ -99,8 +98,8 @@ func (self *BlockPool) Add(b *ethchain.Block, peer *Peer) {
|
|||||||
self.pool[hash] = &block{peer, peer, b, time.Now(), 0}
|
self.pool[hash] = &block{peer, peer, b, time.Now(), 0}
|
||||||
|
|
||||||
if !self.eth.BlockChain().HasBlock(b.PrevHash) && !self.fetchingHashes {
|
if !self.eth.BlockChain().HasBlock(b.PrevHash) && !self.fetchingHashes {
|
||||||
poollogger.Infof("Unknown block, requesting parent (%x...)\n", b.PrevHash[0:4])
|
//poollogger.Infof("Unknown block, requesting parent (%x...)\n", b.PrevHash[0:4])
|
||||||
peer.QueueMessage(ethwire.NewMessage(ethwire.MsgGetBlockHashesTy, []interface{}{b.PrevHash, uint32(256)}))
|
//peer.QueueMessage(ethwire.NewMessage(ethwire.MsgGetBlockHashesTy, []interface{}{b.PrevHash, uint32(256)}))
|
||||||
}
|
}
|
||||||
} else if self.pool[hash] != nil {
|
} else if self.pool[hash] != nil {
|
||||||
self.pool[hash].block = b
|
self.pool[hash].block = b
|
||||||
|
@ -142,14 +142,12 @@ func (self *StateTransition) preCheck() (err error) {
|
|||||||
func (self *StateTransition) TransitionState() (err error) {
|
func (self *StateTransition) TransitionState() (err error) {
|
||||||
statelogger.Debugf("(~) %x\n", self.tx.Hash())
|
statelogger.Debugf("(~) %x\n", self.tx.Hash())
|
||||||
|
|
||||||
/*
|
defer func() {
|
||||||
defer func() {
|
if r := recover(); r != nil {
|
||||||
if r := recover(); r != nil {
|
statelogger.Infoln(r)
|
||||||
logger.Infoln(r)
|
err = fmt.Errorf("state transition err %v", r)
|
||||||
err = fmt.Errorf("state transition err %v", r)
|
}
|
||||||
}
|
}()
|
||||||
}()
|
|
||||||
*/
|
|
||||||
|
|
||||||
// XXX Transactions after this point are considered valid.
|
// XXX Transactions after this point are considered valid.
|
||||||
if err = self.preCheck(); err != nil {
|
if err = self.preCheck(); err != nil {
|
||||||
|
2
peer.go
2
peer.go
@ -320,7 +320,7 @@ out:
|
|||||||
case msg := <-p.outputQueue:
|
case msg := <-p.outputQueue:
|
||||||
if !p.statusKnown {
|
if !p.statusKnown {
|
||||||
switch msg.Type {
|
switch msg.Type {
|
||||||
case ethwire.MsgStatusTy, ethwire.MsgGetTxsTy, ethwire.MsgTxTy, ethwire.MsgGetBlockHashesTy, ethwire.MsgBlockHashesTy, ethwire.MsgGetBlocksTy, ethwire.MsgBlockTy:
|
case ethwire.MsgGetTxsTy, ethwire.MsgTxTy, ethwire.MsgGetBlockHashesTy, ethwire.MsgBlockHashesTy, ethwire.MsgGetBlocksTy, ethwire.MsgBlockTy:
|
||||||
break skip
|
break skip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
122
websocket/client.go
Normal file
122
websocket/client.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
websocket/message.go
Normal file
14
websocket/message.go
Normal file
@ -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)
|
||||||
|
}
|
127
websocket/server.go
Normal file
127
websocket/server.go
Normal file
@ -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
Block a user