aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2014-10-01 05:26:16 +0800
committerobscuren <geffobscura@gmail.com>2014-10-01 05:26:16 +0800
commit6db40ecb22c28a777f4ab1cd4de5a12e41ac669d (patch)
treed444855839bf2e498dc9c4724928c7eb07cf6c22
parent41ae6f298e079a073282de001e6b1eaa51472638 (diff)
downloaddexon-6db40ecb22c28a777f4ab1cd4de5a12e41ac669d.tar.gz
dexon-6db40ecb22c28a777f4ab1cd4de5a12e41ac669d.tar.zst
dexon-6db40ecb22c28a777f4ab1cd4de5a12e41ac669d.zip
WebSocket interface
Web sockets handlers fully implemented. Filter handlers have yet to be implemented.
-rw-r--r--ethereum/flags.go62
-rw-r--r--ethereum/main.go4
-rw-r--r--mist/assets/ext/html_messaging.js28
-rw-r--r--mist/assets/ext/pre.js3
-rw-r--r--mist/assets/ext/qt_messaging_adapter.js21
-rw-r--r--mist/assets/qml/webapp.qml2
-rw-r--r--utils/websockets.go161
7 files changed, 226 insertions, 55 deletions
diff --git a/ethereum/flags.go b/ethereum/flags.go
index c488e6314..58220f4e6 100644
--- a/ethereum/flags.go
+++ b/ethereum/flags.go
@@ -10,36 +10,41 @@ import (
"github.com/ethereum/eth-go/ethlog"
)
-var Identifier string
-var KeyRing string
-var DiffTool bool
-var DiffType string
-var KeyStore string
-var StartRpc bool
-var RpcPort int
-var UseUPnP bool
-var OutboundPort string
-var ShowGenesis bool
-var AddPeer string
-var MaxPeer int
-var GenAddr bool
-var UseSeed bool
-var SecretFile string
-var ExportDir string
-var NonInteractive bool
-var Datadir string
-var LogFile string
-var ConfigFile string
-var DebugFile string
-var LogLevel int
-var Dump bool
-var DumpHash string
-var DumpNumber int
+var (
+ Identifier string
+ KeyRing string
+ DiffTool bool
+ DiffType string
+ KeyStore string
+ StartRpc bool
+ StartWebSockets bool
+ RpcPort int
+ UseUPnP bool
+ OutboundPort string
+ ShowGenesis bool
+ AddPeer string
+ MaxPeer int
+ GenAddr bool
+ UseSeed bool
+ SecretFile string
+ ExportDir string
+ NonInteractive bool
+ Datadir string
+ LogFile string
+ ConfigFile string
+ DebugFile string
+ LogLevel int
+ Dump bool
+ DumpHash string
+ DumpNumber int
+)
// flags specific to cli client
-var StartMining bool
-var StartJsConsole bool
-var InputFile string
+var (
+ StartMining bool
+ StartJsConsole bool
+ InputFile string
+)
func defaultDataDir() string {
usr, _ := user.Current()
@@ -62,6 +67,7 @@ func Init() {
flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers")
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
+ flag.BoolVar(&StartWebSockets, "ws", false, "start websocket server")
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
flag.BoolVar(&UseSeed, "seed", true, "seed peers")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
diff --git a/ethereum/main.go b/ethereum/main.go
index 6521188ff..0f0df20bb 100644
--- a/ethereum/main.go
+++ b/ethereum/main.go
@@ -103,6 +103,10 @@ func main() {
utils.StartRpc(ethereum, RpcPort)
}
+ if StartWebSockets {
+ utils.StartWebSockets(ethereum)
+ }
+
utils.StartEthereum(ethereum, UseSeed)
// this blocks the thread
diff --git a/mist/assets/ext/html_messaging.js b/mist/assets/ext/html_messaging.js
index 1f9418148..91310e998 100644
--- a/mist/assets/ext/html_messaging.js
+++ b/mist/assets/ext/html_messaging.js
@@ -1,9 +1,8 @@
// The magic return variable. The magic return variable will be set during the execution of the QML call.
(function(window) {
- function message(type, data) {
- document.title = JSON.stringify({type: type, data: data});
-
- return window.____returnData;
+ var Promise = window.Promise;
+ if(typeof(Promise) === "undefined") {
+ var Promise = Q.Promise;
}
function isPromise(o) {
@@ -446,6 +445,7 @@
}
});
+
var g_seed = 1;
function postData(data, cb) {
data._seed = g_seed;
@@ -459,24 +459,6 @@
g_seed++;
- navigator.qt.postMessage(JSON.stringify(data));
- }
-
- navigator.qt.onmessage = function(ev) {
- var data = JSON.parse(ev.data)
-
- if(data._event !== undefined) {
- eth.trigger(data._event, data.data);
- } else {
- if(data._seed) {
- var cb = eth._callbacks[data._seed];
- if(cb) {
- cb.call(this, data.data)
-
- // Remove the "trigger" callback
- delete eth._callbacks[ev._seed];
- }
- }
- }
+ window._messagingAdapter.call(this, JSON.stringify(data))
}
})(this);
diff --git a/mist/assets/ext/pre.js b/mist/assets/ext/pre.js
deleted file mode 100644
index f298fe9a1..000000000
--- a/mist/assets/ext/pre.js
+++ /dev/null
@@ -1,3 +0,0 @@
-if(typeof(Promise) === "undefined") {
- window.Promise = Q.Promise;
-}
diff --git a/mist/assets/ext/qt_messaging_adapter.js b/mist/assets/ext/qt_messaging_adapter.js
new file mode 100644
index 000000000..ff6976177
--- /dev/null
+++ b/mist/assets/ext/qt_messaging_adapter.js
@@ -0,0 +1,21 @@
+window._messagingAdapter = function(data) {
+ navigator.qt.postMessage(data);
+};
+
+navigator.qt.onmessage = function(ev) {
+ var data = JSON.parse(ev.data)
+
+ if(data._event !== undefined) {
+ eth.trigger(data._event, data.data);
+ } else {
+ if(data._seed) {
+ var cb = eth._callbacks[data._seed];
+ if(cb) {
+ cb.call(this, data.data)
+
+ // Remove the "trigger" callback
+ delete eth._callbacks[ev._seed];
+ }
+ }
+ }
+}
diff --git a/mist/assets/qml/webapp.qml b/mist/assets/qml/webapp.qml
index dde298484..09e6a83ad 100644
--- a/mist/assets/qml/webapp.qml
+++ b/mist/assets/qml/webapp.qml
@@ -164,7 +164,7 @@ import "../ext/qml_messaging.js" as Messaging
experimental.preferences.javascriptEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true
experimental.preferences.developerExtrasEnabled: true
- experimental.userScripts: ["../ext/q.js", "../ext/pre.js", "../ext/big.js", "../ext/string.js", "../ext/html_messaging.js"]
+ experimental.userScripts: ["../ext/qt_messaging_adapter.js", "../ext/q.js", "../ext/big.js", "../ext/string.js", "../ext/html_messaging.js"]
experimental.onMessageReceived: {
console.log("[onMessageReceived]: ", message.data)
// TODO move to messaging.js
diff --git a/utils/websockets.go b/utils/websockets.go
new file mode 100644
index 000000000..e89331a98
--- /dev/null
+++ b/utils/websockets.go
@@ -0,0 +1,161 @@
+package utils
+
+import (
+ "github.com/ethereum/eth-go"
+ "github.com/ethereum/eth-go/ethpipe"
+ "github.com/ethereum/eth-go/ethutil"
+ "github.com/ethereum/eth-go/websocket"
+)
+
+func args(v ...interface{}) []interface{} {
+ return v
+}
+
+type WebSocketServer struct {
+ ethereum *eth.Ethereum
+ filterCallbacks map[int][]int
+}
+
+func NewWebSocketServer(eth *eth.Ethereum) *WebSocketServer {
+ return &WebSocketServer{eth, make(map[int][]int)}
+}
+
+func (self *WebSocketServer) Serv() {
+ pipe := ethpipe.NewJSPipe(self.ethereum)
+
+ wsServ := websocket.NewServer("/eth", ":40404")
+ wsServ.MessageFunc(func(c *websocket.Client, msg *websocket.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.Seed)
+ }
+
+ code := ethutil.Bytes2Hex(bcode)
+ c.Write(args(code, nil), msg.Seed)
+ case "getBlockByNumber":
+ args := msg.Arguments()
+
+ block := pipe.BlockByNumber(int32(args.Get(0).Uint()))
+ c.Write(block, msg.Seed)
+
+ case "getKey":
+ c.Write(pipe.Key().PrivateKey, msg.Seed)
+ case "transact":
+ if mp, ok := msg.Args[0].(map[string]interface{}); ok {
+ object := mapToTxParams(mp)
+ c.Write(
+ args(pipe.Transact(object["from"], object["to"], object["value"], object["gas"], object["gasPrice"], object["data"])),
+ msg.Seed,
+ )
+
+ }
+ case "getCoinBase":
+ c.Write(pipe.CoinBase(), msg.Seed)
+
+ case "getIsListening":
+ c.Write(pipe.IsListening(), msg.Seed)
+
+ case "getIsMining":
+ c.Write(pipe.IsMining(), msg.Seed)
+
+ case "getPeerCoint":
+ c.Write(pipe.PeerCount(), msg.Seed)
+
+ case "getCountAt":
+ args := msg.Arguments()
+
+ c.Write(pipe.TxCountAt(args.Get(0).Str()), msg.Seed)
+
+ case "getCodeAt":
+ args := msg.Arguments()
+
+ c.Write(len(pipe.CodeAt(args.Get(0).Str())), msg.Seed)
+
+ case "getBlockByHash":
+ args := msg.Arguments()
+
+ c.Write(pipe.BlockByHash(args.Get(0).Str()), msg.Seed)
+
+ case "getStorageAt":
+ args := msg.Arguments()
+
+ c.Write(pipe.StorageAt(args.Get(0).Str(), args.Get(1).Str()), msg.Seed)
+
+ case "getBalanceAt":
+ args := msg.Arguments()
+
+ c.Write(pipe.BalanceAt(args.Get(0).Str()), msg.Seed)
+
+ case "getSecretToAddress":
+ args := msg.Arguments()
+
+ c.Write(pipe.SecretToAddress(args.Get(0).Str()), msg.Seed)
+
+ case "newFilter":
+ case "newFilterString":
+ case "messages":
+ // TODO
+ }
+
+ })
+
+ wsServ.Listen()
+}
+
+func StartWebSockets(eth *eth.Ethereum) {
+ sock := NewWebSocketServer(eth)
+ go sock.Serv()
+}
+
+// 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
+}