mirror of https://github.com/ethereum/go-ethereum
parent
32fbc0d334
commit
726852e3d3
@ -1,126 +0,0 @@ |
||||
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) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,15 +0,0 @@ |
||||
package websocket |
||||
|
||||
import "github.com/ethereum/go-ethereum/ethutil" |
||||
|
||||
type Message struct { |
||||
Call string `json:"call"` |
||||
Args []interface{} `json:"args"` |
||||
Id int `json:"_id"` |
||||
Data interface{} `json:"data"` |
||||
Event string `json:"_event"` |
||||
} |
||||
|
||||
func (self *Message) Arguments() *ethutil.Value { |
||||
return ethutil.NewValue(self.Args) |
||||
} |
@ -1,125 +0,0 @@ |
||||
package websocket |
||||
|
||||
import ( |
||||
"net/http" |
||||
|
||||
"github.com/ethereum/go-ethereum/logger" |
||||
|
||||
ws "code.google.com/p/go.net/websocket" |
||||
) |
||||
|
||||
var wslogger = logger.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() { |
||||
wslogger.Debugln("Serving http", s.httpServ) |
||||
err := http.ListenAndServe(s.httpServ, nil) |
||||
|
||||
wslogger.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() { |
||||
// 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) |
||||
}) |
||||
wslogger.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: |
||||
wslogger.Debugln("Error:", err.Error()) |
||||
|
||||
case <-s.doneCh: |
||||
return |
||||
} |
||||
} |
||||
} |
@ -1,205 +0,0 @@ |
||||
/* |
||||
This file is part of go-ethereum |
||||
|
||||
go-ethereum is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
go-ethereum is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
package websocket |
||||
|
||||
import ( |
||||
"github.com/ethereum/go-ethereum/core" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/eth" |
||||
"github.com/ethereum/go-ethereum/ethutil" |
||||
"github.com/ethereum/go-ethereum/event/filter" |
||||
"github.com/ethereum/go-ethereum/state" |
||||
"github.com/ethereum/go-ethereum/ui" |
||||
"github.com/ethereum/go-ethereum/xeth" |
||||
) |
||||
|
||||
func args(v ...interface{}) []interface{} { |
||||
return v |
||||
} |
||||
|
||||
type WebSocketServer struct { |
||||
eth *eth.Ethereum |
||||
filterManager *filter.FilterManager |
||||
} |
||||
|
||||
func NewWebSocketServer(eth *eth.Ethereum) *WebSocketServer { |
||||
filterManager := filter.NewFilterManager(eth.EventMux()) |
||||
go filterManager.Start() |
||||
|
||||
return &WebSocketServer{eth, filterManager} |
||||
} |
||||
|
||||
func (self *WebSocketServer) Serv() { |
||||
pipe := xeth.NewJSXEth(self.eth) |
||||
|
||||
wsServ := NewServer("/eth", ":40404") |
||||
wsServ.MessageFunc(func(c *Client, msg *Message) { |
||||
switch msg.Call { |
||||
case "compile": |
||||
data := ethutil.NewValue(msg.Args) |
||||
bcode, err := ethutil.Compile(data.Get(0).Str(), false) |
||||
if err != nil { |
||||
c.Write(args(nil, err.Error()), msg.Id) |
||||
} |
||||
|
||||
code := ethutil.Bytes2Hex(bcode) |
||||
c.Write(args(code, nil), msg.Id) |
||||
case "eth_blockByNumber": |
||||
args := msg.Arguments() |
||||
|
||||
block := pipe.BlockByNumber(int32(args.Get(0).Uint())) |
||||
c.Write(block, msg.Id) |
||||
|
||||
case "eth_blockByHash": |
||||
args := msg.Arguments() |
||||
|
||||
c.Write(pipe.BlockByHash(args.Get(0).Str()), msg.Id) |
||||
|
||||
case "eth_transact": |
||||
if mp, ok := msg.Args[0].(map[string]interface{}); ok { |
||||
object := mapToTxParams(mp) |
||||
c.Write( |
||||
args(pipe.Transact(pipe.Key().PrivateKey, object["to"], object["value"], object["gas"], object["gasPrice"], object["data"])), |
||||
msg.Id, |
||||
) |
||||
|
||||
} |
||||
case "eth_gasPrice": |
||||
c.Write("10000000000000", msg.Id) |
||||
case "eth_coinbase": |
||||
c.Write(pipe.CoinBase(), msg.Id) |
||||
|
||||
case "eth_listening": |
||||
c.Write(pipe.IsListening(), msg.Id) |
||||
|
||||
case "eth_mining": |
||||
c.Write(pipe.IsMining(), msg.Id) |
||||
|
||||
case "eth_peerCount": |
||||
c.Write(pipe.PeerCount(), msg.Id) |
||||
|
||||
case "eth_countAt": |
||||
args := msg.Arguments() |
||||
|
||||
c.Write(pipe.TxCountAt(args.Get(0).Str()), msg.Id) |
||||
|
||||
case "eth_codeAt": |
||||
args := msg.Arguments() |
||||
|
||||
c.Write(len(pipe.CodeAt(args.Get(0).Str())), msg.Id) |
||||
|
||||
case "eth_storageAt": |
||||
args := msg.Arguments() |
||||
|
||||
c.Write(pipe.StorageAt(args.Get(0).Str(), args.Get(1).Str()), msg.Id) |
||||
|
||||
case "eth_balanceAt": |
||||
args := msg.Arguments() |
||||
|
||||
c.Write(pipe.BalanceAt(args.Get(0).Str()), msg.Id) |
||||
|
||||
case "eth_accounts": |
||||
c.Write(pipe.Accounts(), msg.Id) |
||||
|
||||
case "eth_newFilter": |
||||
if mp, ok := msg.Args[0].(map[string]interface{}); ok { |
||||
var id int |
||||
filter := ui.NewFilterFromMap(mp, self.eth) |
||||
filter.LogsCallback = func(logs state.Logs) { |
||||
//c.Event(toMessages(messages), "eth_changed", id)
|
||||
} |
||||
id = self.filterManager.InstallFilter(filter) |
||||
c.Write(id, msg.Id) |
||||
} |
||||
case "eth_newFilterString": |
||||
var id int |
||||
filter := core.NewFilter(self.eth) |
||||
filter.BlockCallback = func(block *types.Block) { |
||||
c.Event(nil, "eth_changed", id) |
||||
} |
||||
id = self.filterManager.InstallFilter(filter) |
||||
c.Write(id, msg.Id) |
||||
case "eth_filterLogs": |
||||
filter := self.filterManager.GetFilter(int(msg.Arguments().Get(0).Uint())) |
||||
if filter != nil { |
||||
//c.Write(toMessages(filter.Find()), msg.Id)
|
||||
} |
||||
} |
||||
|
||||
}) |
||||
|
||||
wsServ.Listen() |
||||
} |
||||
|
||||
func toMessages(messages state.Messages) (msgs []xeth.JSMessage) { |
||||
msgs = make([]xeth.JSMessage, len(messages)) |
||||
for i, msg := range messages { |
||||
msgs[i] = xeth.NewJSMessage(msg) |
||||
} |
||||
|
||||
return |
||||
} |
||||
|
||||
// TODO This is starting to become a generic method. Move to utils
|
||||
func mapToTxParams(object map[string]interface{}) map[string]string { |
||||
// Default values
|
||||
if object["from"] == nil { |
||||
object["from"] = "" |
||||
} |
||||
if object["to"] == nil { |
||||
object["to"] = "" |
||||
} |
||||
if object["value"] == nil { |
||||
object["value"] = "" |
||||
} |
||||
if object["gas"] == nil { |
||||
object["gas"] = "" |
||||
} |
||||
if object["gasPrice"] == nil { |
||||
object["gasPrice"] = "" |
||||
} |
||||
|
||||
var dataStr string |
||||
var data []string |
||||
if str, ok := object["data"].(string); ok { |
||||
data = []string{str} |
||||
} |
||||
|
||||
for _, str := range data { |
||||
if ethutil.IsHex(str) { |
||||
str = str[2:] |
||||
|
||||
if len(str) != 64 { |
||||
str = ethutil.LeftPadString(str, 64) |
||||
} |
||||
} else { |
||||
str = ethutil.Bytes2Hex(ethutil.LeftPadBytes(ethutil.Big(str).Bytes(), 32)) |
||||
} |
||||
|
||||
dataStr += str |
||||
} |
||||
object["data"] = dataStr |
||||
|
||||
conv := make(map[string]string) |
||||
for key, value := range object { |
||||
if v, ok := value.(string); ok { |
||||
conv[key] = v |
||||
} |
||||
} |
||||
|
||||
return conv |
||||
} |
Loading…
Reference in new issue