mirror of https://github.com/ethereum/go-ethereum
Conflicts: rpc/message.gopull/272/merge
commit
bd992e7baf
@ -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