Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File loading #17

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions common/channel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
var webSocket = require("ws");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just put this file in lib/? I'm not sure we need another directory.


// A simple websocket abstraction using a emitter/observer pattern
// The api is the same on both the server and the client, but differs in functionality
//
// On the server, channel.send sends the object to all connected clients, while on the client,
// it of course only sends the object to the server
//
// channel.send("type", dataObject);
// channel. on("type", function (receivedDataObject) {...});
//
// on the client, pass a port (integer, not string)
// on the server, pass an HttpServer
// var channel = new Channel(port || HttpServer);
//
// // client
// channel.on("ping", function (data) {
// data.content === "hi there";
// channel.send("pong", {content: "hello", ...});
// });
//
// // server
// channel.on("pong", function (data) {
// data.content === "hello";
// channel.send("ping", {content: "hi there", ...});
// });
//
// Additionally, you can listen to the websocket's onConnection event
// inside the callback, this refers to the channel.
// channel.onConnection(callback);
function Channel (config) {
var that = this;
this.listeners = Object.create(null);
this.connectionListeners = [];

function onMessage (message) {
var data = JSON.parse(message.data);
var type = data.type;

if (type in that.listeners) {
that.listeners[type].forEach(function (listener) {
listener(data);
});
} else {
console.log("Received a message with type '" + type + "' that's not being listened for.");
}
}

function onNewConnection(connection) {
console.log("New websocket connection");
that.connectionListeners.forEach(function (connectionListener) {
connectionListener.call(that, connection);
});

// the client is already listening for messages,
if (that.type === "server") {
connection.on("message", onMessage);
} else {
console.log(connection);
}
}

// on the server side, a channel gets passed an HttpServer, while on the client side it gets passed a port.
// there are small distinctions to make between the server and the client
// the server requires a different websocket constructor, and it talks to multiple clients instead of one.
if (typeof config === "object") {
this.websocket = new webSocket.Server({server: config});
this.type = "server";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be tempted to pass the type in as an argument -- that way it's clear at the call sites what kind of channel you are instantiating. It's a little confusing that the type of channel is determined not by the value of any of the arguments, but by the type of the argument. I think passing in the type as a string would make it a bit less confusing.

Another approach would be to create a ClientChannel and a ServerChannel constructor, and export only those constructors -- they could call the Channel constructor with the appropriate args. I'm fine with whatever you prefer though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think the way it currently is feels a little awkward, I don't like different constructors, because It's supposed to be the same api on the server and on the client.

Maybe something like this?

// client
var channel = new Channel({
  type: Channel.server,
  httpServer: server
});

// client
var channel = new Channel({
  type: Channel.client,
  port: 8080
});

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it. I would just do { type: 'server', ... }, but it's your call.

} else if (typeof config === "number") {
this.websocket = new webSocket("ws://localhost:" + config + "/editor/");
this.type = "client";
}

// for some reason, the websocket api differs on the client from the server
if (this.type === "server") {
this.websocket.on("connection", onNewConnection);
} else {
this.websocket.open = onNewConnection;
}

this.websocket.onmessage = onMessage;
}

Channel.prototype.on = function (messageType, callback) {
if (messageType in this.listeners) {
this.listeners[messageType].push(callback);
} else {
this.listeners[messageType] = [callback];
}
};

Channel.prototype.send = function (messageType, data) {
var message;

data.type = messageType;
message = JSON.stringify(data);

// on the server, send to all clients
// on the client, send to the server
if (this.type === "server") {
this.websocket.clients.forEach(function (client) {
client.send(message);
});
} else {
this.websocket.send(message);
}
};

Channel.prototype.onConnection = function(listener) {
this.connectionListeners.push(listener);
};

module.exports = Channel;
Loading