Skip to content

Commit 6db40ec

Browse files
committed
WebSocket interface
Web sockets handlers fully implemented. Filter handlers have yet to be implemented.
1 parent 41ae6f2 commit 6db40ec

File tree

7 files changed

+226
-55
lines changed

7 files changed

+226
-55
lines changed

ethereum/flags.go

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,41 @@ import (
1010
"github.com/ethereum/eth-go/ethlog"
1111
)
1212

13-
var Identifier string
14-
var KeyRing string
15-
var DiffTool bool
16-
var DiffType string
17-
var KeyStore string
18-
var StartRpc bool
19-
var RpcPort int
20-
var UseUPnP bool
21-
var OutboundPort string
22-
var ShowGenesis bool
23-
var AddPeer string
24-
var MaxPeer int
25-
var GenAddr bool
26-
var UseSeed bool
27-
var SecretFile string
28-
var ExportDir string
29-
var NonInteractive bool
30-
var Datadir string
31-
var LogFile string
32-
var ConfigFile string
33-
var DebugFile string
34-
var LogLevel int
35-
var Dump bool
36-
var DumpHash string
37-
var DumpNumber int
13+
var (
14+
Identifier string
15+
KeyRing string
16+
DiffTool bool
17+
DiffType string
18+
KeyStore string
19+
StartRpc bool
20+
StartWebSockets bool
21+
RpcPort int
22+
UseUPnP bool
23+
OutboundPort string
24+
ShowGenesis bool
25+
AddPeer string
26+
MaxPeer int
27+
GenAddr bool
28+
UseSeed bool
29+
SecretFile string
30+
ExportDir string
31+
NonInteractive bool
32+
Datadir string
33+
LogFile string
34+
ConfigFile string
35+
DebugFile string
36+
LogLevel int
37+
Dump bool
38+
DumpHash string
39+
DumpNumber int
40+
)
3841

3942
// flags specific to cli client
40-
var StartMining bool
41-
var StartJsConsole bool
42-
var InputFile string
43+
var (
44+
StartMining bool
45+
StartJsConsole bool
46+
InputFile string
47+
)
4348

4449
func defaultDataDir() string {
4550
usr, _ := user.Current()
@@ -62,6 +67,7 @@ func Init() {
6267
flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers")
6368
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
6469
flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
70+
flag.BoolVar(&StartWebSockets, "ws", false, "start websocket server")
6571
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
6672
flag.BoolVar(&UseSeed, "seed", true, "seed peers")
6773
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")

ethereum/main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ func main() {
103103
utils.StartRpc(ethereum, RpcPort)
104104
}
105105

106+
if StartWebSockets {
107+
utils.StartWebSockets(ethereum)
108+
}
109+
106110
utils.StartEthereum(ethereum, UseSeed)
107111

108112
// this blocks the thread

mist/assets/ext/html_messaging.js

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
// The magic return variable. The magic return variable will be set during the execution of the QML call.
22
(function(window) {
3-
function message(type, data) {
4-
document.title = JSON.stringify({type: type, data: data});
5-
6-
return window.____returnData;
3+
var Promise = window.Promise;
4+
if(typeof(Promise) === "undefined") {
5+
var Promise = Q.Promise;
76
}
87

98
function isPromise(o) {
@@ -446,6 +445,7 @@
446445
}
447446
});
448447

448+
449449
var g_seed = 1;
450450
function postData(data, cb) {
451451
data._seed = g_seed;
@@ -459,24 +459,6 @@
459459

460460
g_seed++;
461461

462-
navigator.qt.postMessage(JSON.stringify(data));
463-
}
464-
465-
navigator.qt.onmessage = function(ev) {
466-
var data = JSON.parse(ev.data)
467-
468-
if(data._event !== undefined) {
469-
eth.trigger(data._event, data.data);
470-
} else {
471-
if(data._seed) {
472-
var cb = eth._callbacks[data._seed];
473-
if(cb) {
474-
cb.call(this, data.data)
475-
476-
// Remove the "trigger" callback
477-
delete eth._callbacks[ev._seed];
478-
}
479-
}
480-
}
462+
window._messagingAdapter.call(this, JSON.stringify(data))
481463
}
482464
})(this);

mist/assets/ext/pre.js

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
window._messagingAdapter = function(data) {
2+
navigator.qt.postMessage(data);
3+
};
4+
5+
navigator.qt.onmessage = function(ev) {
6+
var data = JSON.parse(ev.data)
7+
8+
if(data._event !== undefined) {
9+
eth.trigger(data._event, data.data);
10+
} else {
11+
if(data._seed) {
12+
var cb = eth._callbacks[data._seed];
13+
if(cb) {
14+
cb.call(this, data.data)
15+
16+
// Remove the "trigger" callback
17+
delete eth._callbacks[ev._seed];
18+
}
19+
}
20+
}
21+
}

mist/assets/qml/webapp.qml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ import "../ext/qml_messaging.js" as Messaging
164164
experimental.preferences.javascriptEnabled: true
165165
experimental.preferences.navigatorQtObjectEnabled: true
166166
experimental.preferences.developerExtrasEnabled: true
167-
experimental.userScripts: ["../ext/q.js", "../ext/pre.js", "../ext/big.js", "../ext/string.js", "../ext/html_messaging.js"]
167+
experimental.userScripts: ["../ext/qt_messaging_adapter.js", "../ext/q.js", "../ext/big.js", "../ext/string.js", "../ext/html_messaging.js"]
168168
experimental.onMessageReceived: {
169169
console.log("[onMessageReceived]: ", message.data)
170170
// TODO move to messaging.js

utils/websockets.go

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package utils
2+
3+
import (
4+
"github.com/ethereum/eth-go"
5+
"github.com/ethereum/eth-go/ethpipe"
6+
"github.com/ethereum/eth-go/ethutil"
7+
"github.com/ethereum/eth-go/websocket"
8+
)
9+
10+
func args(v ...interface{}) []interface{} {
11+
return v
12+
}
13+
14+
type WebSocketServer struct {
15+
ethereum *eth.Ethereum
16+
filterCallbacks map[int][]int
17+
}
18+
19+
func NewWebSocketServer(eth *eth.Ethereum) *WebSocketServer {
20+
return &WebSocketServer{eth, make(map[int][]int)}
21+
}
22+
23+
func (self *WebSocketServer) Serv() {
24+
pipe := ethpipe.NewJSPipe(self.ethereum)
25+
26+
wsServ := websocket.NewServer("/eth", ":40404")
27+
wsServ.MessageFunc(func(c *websocket.Client, msg *websocket.Message) {
28+
switch msg.Call {
29+
case "compile":
30+
data := ethutil.NewValue(msg.Args)
31+
bcode, err := ethutil.Compile(data.Get(0).Str(), false)
32+
if err != nil {
33+
c.Write(args(nil, err.Error()), msg.Seed)
34+
}
35+
36+
code := ethutil.Bytes2Hex(bcode)
37+
c.Write(args(code, nil), msg.Seed)
38+
case "getBlockByNumber":
39+
args := msg.Arguments()
40+
41+
block := pipe.BlockByNumber(int32(args.Get(0).Uint()))
42+
c.Write(block, msg.Seed)
43+
44+
case "getKey":
45+
c.Write(pipe.Key().PrivateKey, msg.Seed)
46+
case "transact":
47+
if mp, ok := msg.Args[0].(map[string]interface{}); ok {
48+
object := mapToTxParams(mp)
49+
c.Write(
50+
args(pipe.Transact(object["from"], object["to"], object["value"], object["gas"], object["gasPrice"], object["data"])),
51+
msg.Seed,
52+
)
53+
54+
}
55+
case "getCoinBase":
56+
c.Write(pipe.CoinBase(), msg.Seed)
57+
58+
case "getIsListening":
59+
c.Write(pipe.IsListening(), msg.Seed)
60+
61+
case "getIsMining":
62+
c.Write(pipe.IsMining(), msg.Seed)
63+
64+
case "getPeerCoint":
65+
c.Write(pipe.PeerCount(), msg.Seed)
66+
67+
case "getCountAt":
68+
args := msg.Arguments()
69+
70+
c.Write(pipe.TxCountAt(args.Get(0).Str()), msg.Seed)
71+
72+
case "getCodeAt":
73+
args := msg.Arguments()
74+
75+
c.Write(len(pipe.CodeAt(args.Get(0).Str())), msg.Seed)
76+
77+
case "getBlockByHash":
78+
args := msg.Arguments()
79+
80+
c.Write(pipe.BlockByHash(args.Get(0).Str()), msg.Seed)
81+
82+
case "getStorageAt":
83+
args := msg.Arguments()
84+
85+
c.Write(pipe.StorageAt(args.Get(0).Str(), args.Get(1).Str()), msg.Seed)
86+
87+
case "getBalanceAt":
88+
args := msg.Arguments()
89+
90+
c.Write(pipe.BalanceAt(args.Get(0).Str()), msg.Seed)
91+
92+
case "getSecretToAddress":
93+
args := msg.Arguments()
94+
95+
c.Write(pipe.SecretToAddress(args.Get(0).Str()), msg.Seed)
96+
97+
case "newFilter":
98+
case "newFilterString":
99+
case "messages":
100+
// TODO
101+
}
102+
103+
})
104+
105+
wsServ.Listen()
106+
}
107+
108+
func StartWebSockets(eth *eth.Ethereum) {
109+
sock := NewWebSocketServer(eth)
110+
go sock.Serv()
111+
}
112+
113+
// TODO This is starting to become a generic method. Move to utils
114+
func mapToTxParams(object map[string]interface{}) map[string]string {
115+
// Default values
116+
if object["from"] == nil {
117+
object["from"] = ""
118+
}
119+
if object["to"] == nil {
120+
object["to"] = ""
121+
}
122+
if object["value"] == nil {
123+
object["value"] = ""
124+
}
125+
if object["gas"] == nil {
126+
object["gas"] = ""
127+
}
128+
if object["gasPrice"] == nil {
129+
object["gasPrice"] = ""
130+
}
131+
132+
var dataStr string
133+
var data []string
134+
if str, ok := object["data"].(string); ok {
135+
data = []string{str}
136+
}
137+
138+
for _, str := range data {
139+
if ethutil.IsHex(str) {
140+
str = str[2:]
141+
142+
if len(str) != 64 {
143+
str = ethutil.LeftPadString(str, 64)
144+
}
145+
} else {
146+
str = ethutil.Bytes2Hex(ethutil.LeftPadBytes(ethutil.Big(str).Bytes(), 32))
147+
}
148+
149+
dataStr += str
150+
}
151+
object["data"] = dataStr
152+
153+
conv := make(map[string]string)
154+
for key, value := range object {
155+
if v, ok := value.(string); ok {
156+
conv[key] = v
157+
}
158+
}
159+
160+
return conv
161+
}

0 commit comments

Comments
 (0)