diff --git a/services/real-time/app/coffee/Router.coffee b/services/real-time/app/coffee/Router.coffee index 2cc655eafc..17107e443a 100644 --- a/services/real-time/app/coffee/Router.coffee +++ b/services/real-time/app/coffee/Router.coffee @@ -79,14 +79,30 @@ module.exports = Router = if err? Router._handleError null, err, client, "leaveProject" - - client.on "joinDoc", (doc_id, fromVersion, callback) -> - # fromVersion is optional - if typeof fromVersion == "function" + # Variadic. The possible arguments: + # doc_id, callback + # doc_id, fromVersion, callback + # doc_id, options, callback + # doc_id, fromVersion, options, callback + client.on "joinDoc", (doc_id, fromVersion, options, callback) -> + if typeof fromVersion == "function" and !options callback = fromVersion fromVersion = -1 + options = {} + else if typeof fromVersion == "number" and typeof options == "function" + callback = options + options = {} + else if typeof fromVersion == "object" and typeof options == "function" + callback = options + options = fromVersion + fromVersion = -1 + else if typeof fromVersion == "number" and typeof options == "object" + # Called with 4 args, things are as expected + else + logger.error { arguments: arguments }, "unexpected arguments" + return callback?(new Error("unexpected arguments")) - WebsocketController.joinDoc client, doc_id, fromVersion, (err, args...) -> + WebsocketController.joinDoc client, doc_id, fromVersion, options, (err, args...) -> if err? Router._handleError callback, err, client, "joinDoc", {doc_id, fromVersion} else diff --git a/services/real-time/app/coffee/WebsocketController.coffee b/services/real-time/app/coffee/WebsocketController.coffee index e0242d4208..53ccecd51b 100644 --- a/services/real-time/app/coffee/WebsocketController.coffee +++ b/services/real-time/app/coffee/WebsocketController.coffee @@ -80,7 +80,7 @@ module.exports = WebsocketController = callback() , WebsocketController.FLUSH_IF_EMPTY_DELAY - joinDoc: (client, doc_id, fromVersion = -1, callback = (error, doclines, version, ops, ranges) ->) -> + joinDoc: (client, doc_id, fromVersion = -1, options, callback = (error, doclines, version, ops, ranges) ->) -> metrics.inc "editor.join-doc" Utils.getClientAttributes client, ["project_id", "user_id"], (error, {project_id, user_id}) -> return callback(error) if error? @@ -91,16 +91,29 @@ module.exports = WebsocketController = return callback(error) if error? DocumentUpdaterManager.getDocument project_id, doc_id, fromVersion, (error, lines, version, ranges, ops) -> return callback(error) if error? + # Encode any binary bits of data so it can go via WebSockets # See http://ecmanaut.blogspot.co.uk/2006/07/encoding-decoding-utf8-in-javascript.html + encodeForWebsockets = (text) -> unescape(encodeURIComponent(text)) escapedLines = [] for line in lines try - line = unescape(encodeURIComponent(line)) + line = encodeForWebsockets(line) catch err logger.err {err, project_id, doc_id, fromVersion, line, client_id: client.id}, "error encoding line uri component" return callback(err) escapedLines.push line + if options.encodeRanges + try + for comment in ranges?.comments or [] + comment.op.c = encodeForWebsockets(comment.op.c) if comment.op.c? + for change in ranges?.changes or [] + change.op.i = encodeForWebsockets(change.op.i) if change.op.i? + change.op.d = encodeForWebsockets(change.op.d) if change.op.d? + catch err + logger.err {err, project_id, doc_id, fromVersion, ranges, client_id: client.id}, "error encoding range uri component" + return callback(err) + AuthorizationManager.addAccessToDoc client, doc_id client.join(doc_id) callback null, escapedLines, version, ops, ranges