Last active
August 29, 2015 14:07
-
-
Save andreastt/b3f7f9c5fc3f01163da1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Represents what we send back to the client. | |
// This is handed down to each individual command | |
// which is allowed to manipulate it using the getters and setters. | |
var Response = function(respHandler, opt_msg, opt_sanitizer) { | |
let sanitizer = function(map) { | |
let rv = {}; | |
for (var [key, value] of map) { | |
if ((typeof value !== undefined) || value !== null) | |
rv[key] = value; | |
} | |
return rv; | |
}; | |
this.respHandler = respHandler; | |
this.sanitizer = opt_sanitizer || sanitizer; | |
let msg = opt_msg || {}; | |
this.data = { | |
name: msg ? msg.name : "Unknown command", | |
sessionId: "sessionId" in msg ? msg["sessionId"] : null, | |
status: "success", | |
value: null | |
}; | |
}; | |
Response.prototype = { | |
send: function() { | |
var rawData = this.sanitizer(this.data); | |
this.respHandler(rawData); | |
}, | |
sendError: function(exc) { | |
this.status = (e instanceof WebDriverError) ? exc.code : "unknown error"; | |
this.value = errors.toJSON(exc); | |
this.send(); | |
}, | |
set name(n) { this.data.name = name }, | |
get name() { return this.data.name }, | |
get sessionId() { return this.data.sessionId }, | |
set sessionId(id) { this.data.sessionId = sessionId }, | |
set status(ns) { this.data.status = ns }, | |
get status() { return this.data.status }, | |
set value(val) { this.data.value = val }, | |
get value() { return this.data.val } | |
}; | |
// CommandProcessor receives messages on execute(…) from Dispatcher, | |
// processes them, and passes them along to MarionetteServer. | |
var CommandProcessor = function(marionetteServer) { | |
this.driver = marionetteServer; | |
}; | |
CommandProcessor.prototype.unmarshal = function(payload) { | |
try { | |
return JSON.parse(payload); | |
} catch (e) { | |
throw new UnknownError("Error parsing payload: " + payload); | |
} | |
}; | |
CommandProcessor.prototype.execute = function(payload, respHandler) { | |
let msg, resp; | |
try { | |
msg = this.unmarshal(payload); | |
resp = new Response(respHandler, msg); | |
this.driver[msg.name](msg.parameters, resp); | |
} catch (e) { | |
response.sendError(e); | |
} | |
}; | |
// Responsible for handling content side commands. | |
function MarionetteListener() { | |
this.startListeners(); | |
} | |
MarionetteListener.prototype.startListeners = function() { | |
addMessageListenerId("Marionette:getCurrentUrl", this.dispatch(this.getCurrentUrl)); | |
}; | |
MarionetteListener.prototype.dispatch = function(func) { | |
return function(msg) { | |
// msg is an IPC construct from the message manager | |
// that contains the data passed from MarionetteServer: | |
// {commandId: "abc", data: {"value": "foo"}} | |
let params = msg.data.value; | |
func(params, resp); | |
// Possibly we have to marshal resp here: | |
sendAsyncMessage("Marionette:done", resp, msg.commandId); | |
}; | |
}; | |
MarionetteListener.prototype.getCurrentUrl = function(cmd, resp) { | |
resp.value = curFrame.location.href; | |
}; | |
var commandSeq = 0; // global | |
// Transparenly proxies any method you call on it to the listener. | |
var ListenerProxy = function() { | |
__noSuchMethod__: function (name, args) { | |
let msg = args; | |
msg.commandId = commandSeq++; | |
this.messageManager.sendAsyncMessage("Marionette:" + name, msg); | |
} | |
}; | |
// Responsible for handling chrome side commands, | |
// like today's MarionetteServerConnection, | |
// and forwarding content side things to the listener. | |
function MarionetteServer() { | |
this.listener = new ListenerProxy(); | |
} | |
MarionetteServer.prototype.getCurrentUrl = function(cmd, resp) { | |
switch (this.context) { | |
case Context.CHROME: | |
resp.value = this.getCurrentWindow().location.href; | |
break; | |
case Context.B2G: | |
resp.value = this.listener.getCurrentUrl(); | |
break; | |
case Context.CONTENT: | |
resp.value = this.curBrowser.tab.linkedContent.contentWindow.location.href; | |
break; | |
} | |
}; | |
// Makes out what is currently MarionetteServerConnection.receiveMessage et.al. | |
function Dispatcher() { | |
this.conn = … | |
this.driver = new MarionetteServer(); | |
this.commandProcessor = new CommandProcessor(this.driver); | |
} | |
// When we receive data on the socket from the client. | |
// Data format is Marionette protocol, | |
// that is a string with a slightly modified JSON structure. | |
Dispatcher.prototype.onPacket: function(packet) { | |
// TOOD: unmarshal transport packet | |
this.commandProcessor.execute(rawData, this.send); | |
}; | |
// Triggered on message from listener. | |
// This data comes as a stringified JSON object. | |
Dispatcher.prototype.receiveMessage = function(msg) { | |
switch (msg.name) { | |
case "Marionette:done": | |
this.send(msg); | |
break; | |
} | |
}; | |
// Callback from commands as well as messages from listener | |
// This message is marshaled and sent back to the client. | |
Dispatcher.prototype.send = function(message) { | |
let payload = JSON.stringify(message); | |
this.conn.send(payload); | |
}; | |
// Data received on the socket _or_ from listener | |
var data = "{name: 'getCurrentUrl', sessionId: '666'}"; | |
// Fake some data received on socket or via IPC from listener | |
var dispatcher = new Dispatcher(); | |
dispatcher.receiveMessage(data); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment