Question about socket.io event hook up in the following code - javascript

In the node.js/socket.io code accompanying this article the following code is used to hook up events:
socket.on('message', function(message) {
var handler = messageFactory[message.messageType];
$chatMessages.append(handler(message));
});
What is the logic/effect of referencing messageFactory as an array (or at least using [] symbols)? Does it create different handles for different messageType?
Thanks!

What is the logic/effect of referencing messageFactory as an array (or at least using [] symbols)? Does it create different handles for different messageType?
messageFactory is an object with two methods chat and system.
I would assume message.messageType is either "chat" or "system"
So messageFactory[message.messageType] simply gets one of the two methods.
Then handler(message) calls that method.
This is becuase messageFactory.chat === messageFactory["chat"]
If you take a look at the server file ("Listing 5: The chatRoom module.") you will see methods returning
return {
messageType: 'system',
text: originalNick + ' changed nick to ' + newNick
};
So the server returns a message object with a messageType property thats read on the client, it appears that messageType is only "chat" or "system".
That code is basically the OO Command Design Pattern. It's running a different command based on the type of object returned

Related

Understanding the wss.clients object in the ws npm package

I am working with the npm ws library on a Node.js server. I was looking at the documentation and found a way to loop through the clients to, for example, send a message to everyone using the wss.clients object:
const WebSocket = require('ws');
const wss = new WebSocket.server({ port:8080 });
//...
wss.clients.forEach(client => {
client.send("A message to you!");
});
I initially thought that wss.clients was an array because it let me iterate through it with the array prototype forEach(), but when I tried running wss.clients.find() on it to send a message only to a specific connection, I got an error:
TypeError: wss.clients.find is not a function
I ran console.log(Array.isArray(wss.clients)) it said false. When I tried console.log(wss.clients), I got an object looking like this:
Set { WebSocket { ... } }
So, my question is, how is the wss.clients object able to run the array prototype forEach()? It worked without using Object.keys() or anything.
I also tried wss.clients.pop() out of curiosity, and it gave another type error.
What really is wss.clients? An object or an array?
I have discovered (thanks to #waiaan) that the type of wss.clients is a Set.
Sets have different methods than arrays, but they are similar.
The best implementation for Set.prototype.find() would be to define a method like this:
Set.prototype.find = function(cb) {
for (const e of this) {
if (cb(e)) {
return e;
}
}
}
More about arrays and sets in this article.

TypeError: Class method is not a function, confused about binding this

I have this class Game.
class Game {
constructor(player) {
this.player1 = player;
}
getHost() {
// player has property nickname
return `Host: ${this.player1.nickname}`;
}
}
I believe the issue I am having is that getHost() is becoming unbound from it's context, however I'm not sure how to fix it. I'm learning JS and I'm pretty confused about this language's usage of this. I'm also using socket.io for the first time, so this adds a lot to the confusion for me.
My server script (the server works, just showing relevant parts):
io.on('connection', (socket) => {
// passed defined player
socket.on('host game', (player) => {
const game = new Game(player);
console.log(game.getHost()); // still works here
io.sockets.emit("game created", game);
});
});
Client:
socket.on("game created", (game) => {
const gameElement = document.createElement("li");
gameElement.innerHTML = game.getHost(); // ERROR
games.appendChild(gameElement);
});
On the above marked line, I get the Uncaught TypeError: game.getHost is not a function.
Sorry if the socket.io functions make it more confusing, basically just when the game is passed from server to client, it doesn't work anymore.
Thanks for the help
The issue is that socketio is serializing the object for you. Since a websocket is still just HTTP, you can't send an actual JS object over it. socketio handles serializing your object to JSON using JSON.stringify(game) behind the scenes. It will also convert that JSON string back into an object for you on the client side too.
Unfortunately when you do this you lose methods. For example:
let game = new Game({nickname: 'Bob Vance'});
game = JSON.stringify(game);
console.log(game) // will output {"player1":{"nickname":"Bob Vance"}}
You should see {"player1":{"nickname":"Bob Vance"}} in the console because serializing to JSON drops the methods but preserves properties. This is just normal JavaScript behaviour.
So what you have to do to get the methods back is create a new instance of a game on the client-side, and then use Object.assign() to build the object back up.
Example
let serializedGame= JSON.parse(game);
let newGameInstance = new Game({nickname: game.nickname});
Object.assign(newGameInstance, serializedGame);
Now you should be ok to call newGameInstance.getHost()

Ramda: access input object's properties inside R.ifElse() function call

I have this existing function:
const inferProcessingError = R.ifElse(
R.propEq('conversionJobStatus', 3),
R.always('Last Process failed with error; please contact DevOps'),
R.always(null)
);
which is called like this:
const msg = inferProcessingError(jobStruct || {});
with this jobStruct:
{"id":9,"mediaGroupId":1000000,"conversionJobStatus":3,
"errorDetails": {
"Cause": {
"errorMessage": "MediaConvert Job Failed with ERROR status: ERROR Video codec [indeo4] is not a supported input video codec",
},
"Error": "Error",
}
}
and I need to create an error message string which includes the data from the Cause.errorMessage element.
This would be dead simple with a native JavaScript function, but I'm learning Ramda and want to just modify the existing code to include in the error message.
An R.prop('Cause')['errorMessage'] could work except that I can't figure out how to reference the jobStruct that was passed in to the inferProcessingError statement.
I can see that the R.ifElse and subsequent Ramda functions are able to get that reference, but when I embed an R.prop('Cause') in the error message string, it resolves to a function and not the value of the Cause element because it seems to be waiting for the data structure.
So...how do I gain access to the jobStruct reference? (arguments is not defined here).
UPDATE:
I can get this to work by referencing the original jobStruct as in R.Prop('ErrorDetails', jobStruct)['Cause']['errorMessage'] but that seems rather kludgy to me...
BUT if the call to inferProcessingError is actually inside a map statement and references an element in a larger structure, then the map index is not available to reference the data structure for the R.prop.
Perhaps you could use the pipe and path methods to achieve this "the ramda way".
Begin by using ramda's path() function to extract the nested errorMessage value from the input jobStruct object. Next, enclose that in a pipe() that transforms the extracted message into a string formatted with a custom error prefix:
const incCount = R.ifElse(
R.propEq('conversionJobStatus', 3),
/* Evaluate this pipe if the error case is satisfied */
R.pipe(
/* Path to extract message from input object */
R.path(["errorDetails", "Cause", "errorMessage"]),
/* Prefix string to extracted error message */
R.concat('Custom error prefix:')),
R.always('')
);
incCount({"id":9,"mediaGroupId":1000000,"conversionJobStatus":3,
"errorDetails": {
"Cause": {
"errorMessage": "MediaConvert Job Failed with ERROR etc etc",
},
"Error": "Error",
}
});
Here's a working example - hope that helps!
Update
Thanks to #customcommander for the suggestion to use concat for the string prefix, as well as returning an empty string value for the second branch

Active X control custom events fail to fire in Javascript

I have written a custom active X control using the IDispatch interface that I would like to communicate with javascript. I have successfully gotten the javascript -> COM path working; I can call a javascript function on my active x object and receive a corresponding INVOKE call in my dll.
To receive events on the javascript side, I am following the advice in this article: http://jeffcode.blogspot.com/2008/02/how-to-create-activex-control-that.html
When I load my test page, I get a call to FindConnectionPoint followed by a call to Advise, as I would expect. When I call Invoke on the interface given by Advise, I get a success status message, but nothing happens on the js side!
This is the javascript code I am using to test event handling:
function FooActiveX::ReceiveMessage(msg)
{
alert(msg);
}
Interestingly, if I remove that, I don't get the calls to FindConnectionPoint or Advise anymore, so it's doing SOMETHING.
Any advice on how to debug this problem or things to try would be very helpful. Thank you!
My idl interface definition file looks like this:
[
uuid("1bf6bb1a-3232-11e4-a195-a6c5e4d22fb7"),
version(1.0),
]
library FooControlLib
{
interface IFooControl;
dispinterface DFooControlEvents;
importlib("stdole2.tlb");
[
uuid("1bf6bb1a-3232-11e4-a195-a6c5e4d22fb8"),
hidden
]
dispinterface DFooControlEvents
{
properties:
methods:
[id(DISPID_RECEIVEMESSAGE)] void ReceiveMessage( [in] BSTR msg );
}
[
odl,
dual,
uuid("1bf6bb1a-3232-11e4-a195-a6c5e4d22fb9"),
oleautomation
]
interface IFooControl : IDispatch
{
[id(DISPID_SENDMESSAGE)] HRESULT SendMessage( [in] BSTR msg);
}
[
uuid("1bf6bb1a-3232-11e4-a195-a6c5e4d22fc0")
]
coclass FooControl
{
[default] interface IFooControl;
[source, default] dispinterface DFooControlEvents;
}
}
EDIT: It seems that the problem is related to the parameter in the ReceiveMessage method. If I remove the "msg" parameter, the alert box will display properly.
Found my problem. The arguments to the method are passed to Invoke as an array of VARIANTARG structures. I had set the value, but not the vt member of that struct, which identifies the type of the parameter. I don't know why invoke returned an OK status.

Store and retrieve Google Dart objects in JavaScript library containers

Store and retrieve Google Dart objects in JavaScript library containers
In a Dart application I am using an external JavaScript library to do various matrix calculations.
The specific functionality of the library is not important, what it's important is that I need to store and retrieve Dart object that I put in the matrix.
Dart Class - Lets image i have a dart object that which has a parameter called name
MyDartClass mydc = new MyDartClass(something, something);
mydc.name;
// Everything works as planned
Storing
matrix = js.context.matrix
matrix.cell(1,1).store("thing", new MyDartClass(something, something));
Retrieving
matrix.cell(1,1).has_object_of_type("thing");
// true
MyDartClass mydc = matrix.cell(1,1).retrieve("thing");
Do something with the object
mydc.name;
// Exception: The null object does not have a getter 'name'.
// NoSuchMethodError : method not found: 'name'
// Receiver: null
// Arguments: []
Does the library really work?
Yes it does. I have done the exact same thing in pure javascript many times and there are plenty of test to test the behaviour ( in Javascript )
Is Dart Broken?
When I try to use a javascriptified Hash to do the same behavoiur it works like a charm.
var options = js.map({ 'dart' : new MyDartclass(something, something));
var y = options["dart"];
js.context.console.log(y.name);
// Name is printed
What do you get out from the retrieve?
It seems that I get some kind of Dart Proxy
MyDartClass mydc = matrix.cell(1,1). retrieve("thing");
js.context.console.log(mydc);
DartProxy {id: "dart-ref-20", port: DartSendPortSync}
id: "dart-ref-20"
port: DartSendPortSync
__proto__: DartProxy
I belive that the lib stores the objects, deep down, in a hash map. But it seems like when I retrieve the object into the Dart I get something, but not in a way that I can work with it. So i need help since I don't know how to make it work.
Do I need to de-proxify the object?
Perhaps it IS a Dart bug when you try to retrieve objects from hashes inside objects
Perhaps I missunderstod everything that this is not suppose to work.
Passing and retrieving Dart objects inside the same scope is working. There's the following test case in the tests of js-interop to proove it :
test('retrieve same dart Object', () {
final date = new DateTime.now();
js.context.dartDate = date;
expect(js.context.dartDate, equals(date));
});
However there seems to be an issue with multiple scopes (and multiple event loops as well). There is no way to retain a dart object for now. So your dart object reference goes away at the end of scope. Here's a simple test case that fails :
test('retrieve same dart Object', () {
final date = new DateTime.now();
js.scoped(() {
js.context.dartDate = date;
});
js.scoped(() {
expect(js.context.dartDate, equals(date));
});
});
Please file an issue.

Categories