I'm new to Blockchain and I want to understand how to use JS to open a Websocket, the code is from Blockcypher.com docs https://www.blockcypher.com/dev/dash/?javascript#using-websockets
// Get latest unconfirmed transactions live
var ws = new WebSocket("wss://socket.blockcypher.com/v1/dash/main");
var count = 0;
ws.onmessage = function (event) {
var tx = JSON.parse(event.data);
var shortHash = tx.hash.substring(0, 6) + "...";
var total = tx.total / 100000000;
var addrs = tx.addresses.join(", ");
$('#browser-websocket').before("<div>Unconfirmed transaction " + shortHash + " totalling " + total + "DASH involving addresses " + addrs + "</div>");
count++;
if (count > 10) ws.close();
}
ws.onopen = function(event) {
ws.send(JSON.stringify({event: "unconfirmed-tx"}));
}
The browser console displays this error: Firefox can’t establish a connection to the server at wss://socket.blockcypher.com/v1/dash/main.
Note: I have a token provided by Blockcypher but the code example they provide doesn't ask for any token. Is the code bad? is it missing something?
The problem is not in your code but with the server not responding as expected.
It could be a server issue or you may need to be pre approved to access the resource (assuming they are whitelisting IP addresses which I doubt).
Also, check out the rest of the code, it has a placeholder for a token that you may need to connect (the error you see now is way before the token is requested).
You can always change the server name to one of many test servers out there like wss://echo.websocket.org and see the error changing from "Can't establish connection" to something related to the rest of the code.
Related
(note, I'm using Node.js to create a telnet server and handle user input)
I'm having issues using variables/arrays in javascript inside functions in other scripts.
Let me set a simpler example:
var connections = []
is an array in my main.js
Broadcast.js is a function I put in a separate module and attempt to use the broadcast() function in my main.js.
The error I get is stating that connections is undefined. How do get Broadcast.js able to see the connections array in the main.js
~~
For example in my main.js I set an array to handle clients connecting to a server
//point to Telnet library
const Telnet = require('ranvier-telnet');
const logger = require('./logger.js')
var outspeak = []
var connections = []
var clients = []
let server = new Telnet.TelnetServer(rawSocket => {
let telnetSocket = new Telnet.TelnetSocket();
//attaching socket
telnetSocket.attach(rawSocket);
//setting telnet options
telnetSocket.telnetCommand(Telnet.Sequences.WILL, Telnet.Options.OPT_EOR);
//giving clients a name
telnetSocket.name = rawSocket.remoteAddress + ":" + rawSocket.remotePort
//pushing client names to array
clients.push(telnetSocket.name);
//pushing client connections to an array
connections.push(rawSocket);
console.log(`${telnetSocket.name} has connected`)
logger(`${telnetSocket.name} has connected`)
broadcast(telnetSocket.name + " connected.")
telnetSocket.on('data', function (data) {
//broadcast (telnetSocket.name + ">" + data, telnetSocket);
}
function broadcast (message, sender) {
connections.forEach(function (connection) {
//don't want to send it to sender
if (connection === sender) return;
connection.write(`${message} \n`);
});
}
Now inside my main script, I could called that array/push to that array, read from that array, as long as I type out the function inside the main.js file.
And it can easily use the broadcast function.
Now I want to make it more advance and make reduce my lines on my main.js
but once I separate the broadcast function into it's own module.
use strict'
//broadcast function
function broadcast (message, sender) {
connections.forEach(function (connection) {
//don't want to send it to sender
if (connection === sender) return;
connection.write(`${message} \n`);
});
}
module.exports = broadcast
I get a connection undefined error any time I try to invoke that broadcast function. It's like my global variable/array can't be seen by broadcast.js function.
this is how I'm invoking it
// handle input
telnetSocket.on('data', function (data) {
broadcast (telnetSocket.name + ">" + data, telnetSocket);
});
And yes, const broadcast = require('./broadcast.js'); as been added to the file at the top.
Here's the broken code complete:
'use strict'
//point to Telnet library
const Telnet = require('ranvier-telnet');
const logger = require('./logger.js');
const broadcast = require('./broadcast.js');
var connections = []
var clients = []
//had to call message as global variable
//Asan's timestamp functionm
//telnetstuff
console.log("Starting...");
let server = new Telnet.TelnetServer(rawSocket => {
let telnetSocket = new Telnet.TelnetSocket();
//attaching socket
telnetSocket.attach(rawSocket);
//setting telnet options
telnetSocket.telnetCommand(Telnet.Sequences.WILL, Telnet.Options.OPT_EOR);
//giving clients a name
telnetSocket.name = rawSocket.remoteAddress + ":" + rawSocket.remotePort
//pushing client names to array
clients.push(telnetSocket.name);
//pushing client connections to an array
connections.push(rawSocket);
console.log(`${telnetSocket.name} has connected`)
logger(`${telnetSocket.name} has connected`)
broadcast(telnetSocket.name + " connected.")
// handle input
telnetSocket.on('data', function (data) {
broadcast (telnetSocket.name + ">" + data, telnetSocket);
});
//removing client/connection from array
rawSocket.on('end', function () {
clients.splice(clients.indexOf(telnetSocket), 1);
connections.splice(connections.indexOf(rawSocket), 1);
broadcast(telnetSocket.name + " has left.\n");
logger(telnetSocket.name + " has left.");
console.log(telnetSocket.name + " has left.");
});
}).netServer
server.listen(4000);
console.log('ServerRunning...');
logger('>Server started.');
What I'm missing here? Also I apologize in advance this is my first question ever asked and I've gone through as much I could today to even figure out how to ask my question, maybe I'm not using correct lingo/terms? any help is appreciative.
refactor\broadcast.js:5
connections.forEach(function (connection) {
^
ReferenceError: connections is not defined
In nodejs, when you declare a variable not inside any function definitions, it is scoped to the file only. (This is different from browser javascript.) If you want something to be accessible from outside, you need to export it:
module.exports.connections = connections;
Then import it into the other file:
const connections = require(myFile);
This will work as long as you don't try to set the value of the variable in either file, but if you do that they'll end up pointing to separate objects. But mutating it, calling methods on it, etc should work fine.
I am trying to create Server-Sent events on my Ruby Grape API.
The problem is that the connection seems to be closed really fast all the time, as I get Connection closed event all the time on test webpage.
The client connects to the server as I can see the method being called, but I would like to know why is the connection not constant and why I don't receive the data I send using the Thread.
Here is my Ruby code:
$connections = []
class EventsAPI < Sinantra::Base
def connections
$connections
end
get "/" do
content_type "text/event-stream"
stream(:keep_open) { |out|
puts "New connection"
out << "data: {}\n\n"
connections << out
}
end
post "/" do
data = "data\n\n"
connections.each { |out| out << data }
puts "sent\n"
end
end
Here is my Javascript:
var source = new EventSource('http://localhost:9292/events');
source.onmessage = function(e) {
console.log("New message: ", e.data);
showMessage(e.data);
};
source.onopen = function(e) {
// Connection was opened.
};
source.onerror = function(e) {
console.log("Source Error", e)
if (e.eventPhase == EventSource.CLOSED) {
console.log("Connection was closed");
// Connection was closed.
}
};
var showMessage = function(msg) {
var out = document.getElementById('stream');
var d = document.createElement('div')
var b = document.createElement('strong')
var now = new Date;
b.innerHTML = msg;
d.innerHTML = now.getHours() + ":" + now.getMinutes() + ":" +now.getSeconds() + " ";
d.appendChild(b);
out.appendChild(d);
};
EDIT: I got it working with the GET method (I changed the Grape::API to Sinatra::Base as Grape does not implement stream). I now receive data, but the connection is not kept alive and when I use the post method the data never reaches the browser.
Thank you in advance for your answers.
The JS code looks correct. My guess is that you should not start a new thread for your infinite loop. What will be happening is that the main thread will carry on executing, reach the end of its block, and close the http request. Your detached thread is then left writing to a non-existent out stream.
UPDATE in response to your EDIT: POST is not supported in SSE. Data can only be passed to an SSE process by using GET data or cookies.
I'm currently running into a problem you guys might be able to help me with..
I'm using websockets to connect to a custom server. Now i want to integrate a second Server IP if the first one isn't available.
How is it possible to detect, that the connection couldn't be made because the server isn't reachable? When I enter a wrong ws://url in my script, Chrome for example gives me the following error:
WebSocket connection to 'wss://1234/' failed: Error in connection establishment: net::ERR_NAME_NOT_RESOLVED
in Firefox it's something complete different. Do you guys of any method to catch this error with Javascript?
Basically when the ws:// url can't be reached, i want to change a variable with a different Server-IP and try it with this one again...
Thanks for your help!
It seems there's no way to catch the problem on instantiation, even though the magical JavaScript black box somehow seems to know the problem occurs on the new WebSocket.
To detect this error, use the following:
ws = new WebSocket(server);
ws.onerror = function (evt) {
if (ws.readyState == 3) {
//Connection closed.
}
}
thanks #orbitbot,
I'm using a framework called jwebsocket (jwebsocket.org). My Code is basically this:
serverstate = "0";
console.log(serverstate);
function logon() {
if(serverstate == "0") {
lURL = "wss://testurl-one:9797";
} else if (serverstate == "1") {
lURL = "wss://testurl-two:9797";
}
var gUsername = "user";
var lPassword = "pass";
console.log( "Connecting to " + lURL + " and console.logging in as '" + gUsername + "'..." );
var lRes = lWSC.logon( lURL, gUsername, lPassword, {
// OnOpen callback
OnOpen: function( aEvent ) {
console.log( "jWebSocket connection established." );
},
// OnMessage callback
OnMessage: function( aEvent, aToken ) {
var lDate = "";
if( aToken.date_val ) {
lDate = jws.tools.ISO2Date( aToken.date_val );
}
console.log( "jWebSocket '" + aToken.type + "' token received, full message: '" + aEvent.data + "' " + lDate + "" );
console.log(aToken);
}
},
// OnClose callback
OnClose: function( aEvent ) {
console.log( "Disconnected from Server" );
console.log("Using next server..");
serverstate = "1";
console.log(serverstate);
console.log("Trying to connect to next server");
logon();
},
// OnClose callback
OnError: function( aEvent ) {
console.log ("Some error appeared");
}
});
console.log( lWSC.resultToString( lRes ) );
}
Of course this would work so far. My Problem is that im using websockets to open a connection, get some information, and after that close the connection again.
since this code will always be fired if the server connection is closed (which in many cases i want to..) i can't use it like that...
any other ideas on this problem ?
I got it.. for everyone else who's interested:
When connection is made you receive a message from there server. So if the server is not available.. there'll be no message. So i just added a variable to the "OnMessage" Part.. and in the disconnect i check if a message was received. If not the server isn't there.. if yes, everything works fine..
Assuming your code is something like this,
var host = 'ws://a.real.websocket.url';
var socket = new WebSocket(host);
... you just need to surround the call to new WebSocket with a try/catch block, something like this
try {
var socket = new WebSocket(host);
} catch (e) {
// inspect e to understand why there was an error
// and connect to another url if necessary
}
That being said, it might be easier to work with a websockets library such as Socket.IO or SockJS (https://github.com/sockjs/sockjs-client), which then would change your reconnection code logic to whatever the libraries provide.
Can the following VB Script to open an IP cash drawer be done in Javascript instead?
Private Sub CashDrawerConnect_Click()
Winsock1.Close
ipaddr = "192.168.2.5"
Winsock1.RemoteHost = ipaddr
Winsock1.RemotePort = 30998
Winsock1.Connect
Sleep 250
TxtOpStatus = "Connection to the cash drawer at " & ipaddr & " is established..."
TxtOpStatus.Refresh
End Sub
Private Sub CashDrawerOpen_Click()
If Winsock1.State = sckConnected Then
Winsock1.SendData "opendrawer\0a"
Else
TxtOpStatus = "Not connected to the device"
TxtOpStatus.Refresh
End If
End Sub
You could do it on javascript, but not while running on a browser.
You would need to install nodejs and run your js file directly from the console.
This is a small example that would connect you the the drawer and send the "opendrawer" command on your example:
var net = require('net');
var client = net.connect({port: 30998, host: "yourip"}, function() {
client.write("opendrawer\0a");
});
If however the server has access to the drawer the javascript code could just make a request to the server which would be on charge of opening the connection to the drawer and sending the payload (opendrawer).
If you use php you can take a look at the sockets documentation.
Using VB and JavaScript the calls are mostly the same, you just jhave to adapt it to the language. http://www.ostrosoft.com/oswinsck/oswinsck_javascript.asp
The following is a snippet that uses WinSock from JScript
var oWinsock;
var sServer = "192.168.2.5";
var nPort = 3098;
var bClose = false;
oWinsock = new ActiveXObject("OSWINSCK.Winsock");
// Hooking up handlers
WScript.ConnectObject(oWinsock, "oWinsock_");
oWinsock.Connect(sServer, nPort);
WScript.Echo("Invalid URL");
bClose = true;
function oWinsock_OnConnect() {
oWinsock.SendData('Your data');
}
function oWinsock_OnDataArrival(bytesTotal) {
var sBuffer = oWinsock.GetDataBuffer();
sSource = sSource + sBuffer;
}
function oWinsock_OnError(Number, Description, Scode, Source,
HelpFile, HelpContext, CancelDisplay) {
WScript.Echo(Number + ': ' + Description);
}
function oWinsock_OnClose() {
oWinsock.CloseWinsock();
WScript.Echo(sSource);
oWinsock = null;
bClose = true;
}
while (!bClose) {
WScript.Sleep(1);
}
In the browser? Not really, but you can use WebSockets http://en.wikipedia.org/wiki/WebSocket
You'll need to implement a WebSocket server, so if you need to talk directly to a socket, you can't do it from a browser. But you could implement a proxy server that relays information between the socket server and the WebSocket server.
If you don't need two way communication, the best thing would be for your server to provide a webservice that wraps that socket request. Then your client can just make an AJAX call.
I'm trying to get UDP sockets working for a packaged app using Chrome Canary (currently version 25). I am pretty confused by the fact the UDP example here conflicts with the reference documentation here.
The official example uses this line:
chrome.socket.create('udp', '127.0.0.1', 1337, { onEvent: handleDataEvent }, ...
In Canary using this line results in the error:
Uncaught Error: Invocation of form socket.create(string, string,
integer, object, function) doesn't match definition
socket.create(string type, optional object options, function callback)
Not surprising since that matches the documented form of the function. (I guess the example is out of date?) OK, so I try this...
chrome.socket.create('udp', { onEvent: handleDataEvent }, ...
Canary complains:
Uncaught Error: Invalid value for argument 2. Property 'onEvent':
Unexpected property.
Now I'm confused, especially since this parameter is undocumented in the reference. So I just go with this:
chrome.socket.create('udp', {}, ...
Now it creates OK, but the following call to connect...
chrome.socket.connect(socketId, function(result) ...
...fails with this:
Uncaught Error: Invocation of form socket.connect(integer, function)
doesn't match definition socket.connect(integer socketId, string
hostname, integer port, function callback)
...which is not surprising, since now my code doesn't mention a host or port anywhere, so I guess it needs to be in connect. So I change it to the form:
chrome.socket.connect(socketId, address, port, function (result) ...
At last I can connect and write to the socket OK. But this doesn't cover reading.
Can someone show me a working example based on UDP that can send & receive, so I can work from that?
How do I receive data since the example's onEvent handler does not work? How do I ensure I receive any data on-demand as soon as it arrives without blocking?
The Network Communications doc is not up-to-date. See the latest API doc: https://developer.chrome.com/trunk/apps/socket.html. But the doc doesn't state everything clearly.
I looked into Chromium source code and found some useful comments here: https://code.google.com/searchframe#OAMlx_jo-ck/src/net/udp/udp_socket.h&q=file:(%5E%7C/)net/udp/udp_socket%5C.h$&exact_package=chromium
// Client form:
// In this case, we're connecting to a specific server, so the client will
// usually use:
// Connect(address) // Connect to a UDP server
// Read/Write // Reads/Writes all go to a single destination
//
// Server form:
// In this case, we want to read/write to many clients which are connecting
// to this server. First the server 'binds' to an addres, then we read from
// clients and write responses to them.
// Example:
// Bind(address/port) // Binds to port for reading from clients
// RecvFrom/SendTo // Each read can come from a different client
// // Writes need to be directed to a specific
// // address.
For the server UDP socket, call chrome.socket.bind and chrome.socket.recvFrom/chrome.socket.sendTo to interact with clients. For the client UDP socket, call chrome.socket.connect and chrome.socket.read/chrome.socket.write to interact with the server.
Here's an example:
var serverSocket;
var clientSocket;
// From https://developer.chrome.com/trunk/apps/app_hardware.html
var str2ab=function(str) {
var buf=new ArrayBuffer(str.length);
var bufView=new Uint8Array(buf);
for (var i=0; i<str.length; i++) {
bufView[i]=str.charCodeAt(i);
}
return buf;
}
// From https://developer.chrome.com/trunk/apps/app_hardware.html
var ab2str=function(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
};
// Server
chrome.socket.create('udp', null, function(createInfo){
serverSocket = createInfo.socketId;
chrome.socket.bind(serverSocket, '127.0.0.1', 1345, function(result){
console.log('chrome.socket.bind: result = ' + result.toString());
});
function read()
{
chrome.socket.recvFrom(serverSocket, 1024, function(recvFromInfo){
console.log('Server: recvFromInfo: ', recvFromInfo, 'Message: ',
ab2str(recvFromInfo.data));
if(recvFromInfo.resultCode >= 0)
{
chrome.socket.sendTo(serverSocket,
str2ab('Received message from client ' + recvFromInfo.address +
':' + recvFromInfo.port.toString() + ': ' +
ab2str(recvFromInfo.data)),
recvFromInfo.address, recvFromInfo.port, function(){});
read();
}
else
console.error('Server read error!');
});
}
read();
});
// A client
chrome.socket.create('udp', null, function(createInfo){
clientSocket = createInfo.socketId;
chrome.socket.connect(clientSocket, '127.0.0.1', 1345, function(result){
console.log('chrome.socket.connect: result = ' + result.toString());
});
chrome.socket.write(clientSocket, str2ab('Hello server!'), function(writeInfo){
console.log('writeInfo: ' + writeInfo.bytesWritten +
'byte(s) written.');
});
chrome.socket.read(clientSocket, 1024, function(readInfo){
console.log('Client: received response: ' + ab2str(readInfo.data), readInfo);
});
});