Permalink
Browse files

made the api

  • Loading branch information...
1 parent c03dea6 commit 9a86038bf60c47256e4f8b4ee2f6f425cd4e90a6 Bradley Meck committed Jul 14, 2010
View
@@ -0,0 +1,121 @@
+//@theory
+var Synchronizer = exports.Synchronizer = function Synchronizer() {
+ //this.sockets = []
+ //this.doc = undefined
+}
+
+
+//update all clients to current value
+Synchronizer.prototype.sync = function(callback/*(err)*/) {
+ //this.sockets.forEach(socket) {socket.write(this.doc)}
+ //callback(false)
+}
+
+
+//someone posts an update
+Synchronizer.prototype.save = function(doc_or_stream,callback/*(err)*/) {
+ //this.doc = doc
+ //callback(false)
+}
+
+
+//someone requests doc
+Synchronizer.prototype.get = function(callback/*(err,doc)*/) {
+ //callback(false,this.doc)
+}
+
+
+//client connects
+Synchronizer.prototype.open = function(websocket,callback/*(err)*/) {
+ //callback(EventEmitter)
+ // -edit
+ // -open
+ // -quit
+}
+
+
+//client closes
+Synchronizer.prototype.close = function(websocket,callback/*(err)*/) {
+ //callback()
+}
+
+
+//@use
+var SynchronizedText = exports.SynchronizedText = function SynchronizedText(name) {
+ this.name = name
+ this.id = 0
+ this.clients = []
+ this.doc = ""
+}
+SynchronizedText.prototype = new Synchronizer
+
+
+SynchronizedText.prototype.sync = function(callback) {
+ var $this = this
+ this.clients.forEach(function(client){
+ var data = $this.name+"@"+$this.doc
+ client.websocket.write(data)
+ })
+ if(callback) callback(false)
+}
+
+
+//TODO: Resolve merge errors...
+SynchronizedText.prototype.save = function(doc,callback) {
+ if(typeof doc === "string") {
+ this.doc = doc
+ this.sync()
+ if(callback) callback(false)
+ if(this.onupdate) this.onupdate(doc)
+ }
+ else {
+ var _tmp = String()
+ , $this = this
+ doc.addListener("data",function(chunk){_tmp += String(chunk)})
+ doc.addListener("close",function(){
+ $this.doc = _tmp
+ $this.sync()
+ if(callback) callback(false)
+ if($this.onupdate) $this.onupdate(_tmp)
+ })
+ }
+}
+
+
+SynchronizedText.prototype.get = function(callback) {
+ if(callback) callback(false,this.doc)
+}
+
+
+SynchronizedText.prototype.open = function(websocket,callback) {
+ var $this = this
+ , listener = function(chunk) {
+ chunk = String(chunk)
+ var index = chunk.indexOf("@")
+ if(index !== -1) {
+ var target = chunk.slice(0,index)
+ if(target === $this.name) {
+ var doc = $this.doc = chunk.slice(index+1)
+ $this.sync()
+ if($this.onupdate) $this.onupdate(doc)
+ }
+ }
+ }
+ this.clients.push({websocket:websocket,listener:listener})
+ websocket.addListener("message",listener)
+ var data = this.name+"@"+this.doc
+ websocket.write(data)
+ if(callback) callback(false)
+}
+
+
+SynchronizedText.prototype.close = function(websocket,callback) {
+ var notFound = true
+ this.clients.forEach(function(client){
+ if(client.websocket === websocket) {
+ notFound = false
+ websocket.removeListener("message",client.listener)
+ }
+ })
+ if(callback) callback(notFound)
+}
View
@@ -0,0 +1,39 @@
+var connect = require('connect')
+ , ws = require('websocket-server')
+ , sys = require('sys')
+ , SynchronizedText = require('./api').SynchronizedText
+
+var input = new SynchronizedText('input')
+ , input_color = new SynchronizedText('input.color')
+input.onupdate = function(doc) {
+ input_color.save(doc)
+}
+var texts = [
+ new SynchronizedText('textarea')
+ , input
+ , input_color
+]
+
+server = ws.createServer(
+ {
+ //let http fall through to sub-server
+ handleEvents: false
+ }
+ , connect.createServer(
+ connect.staticProvider(__dirname + '/static')
+ )
+)
+server.addListener("connection", function (conn) {
+ sys.puts("opened connection: "+conn.id);
+ //sys.puts(Object.keys(conn))
+ conn.addListener("message", function(message){
+ sys.puts("<"+conn.id+"> "+message);
+ });
+ //registration w/ text
+ texts.forEach(function(text){text.open(conn)})
+ //close causes unregistration w/ text
+ conn.addListener("close", function () {
+ texts.forEach(function(text){text.close(conn)})
+ })
+})
+server.listen(8888)
View
@@ -0,0 +1,67 @@
+//@theory
+Synchronizer = function(){}
+
+
+//@use
+SynchronizedText = function(name) {
+ this.name = name
+ this.id = 0
+ this.clients = []
+ this.doc = ""
+}
+SynchronizedText.prototype = new Synchronizer
+
+
+//TODO: Resolve merge errors...
+SynchronizedText.prototype.save = function(doc,callback) {
+ this.doc = doc
+ this.sync()
+ if(callback) callback(false)
+}
+
+
+SynchronizedText.prototype.sync = function(callback) {
+ var name = this.name
+ , doc = this.doc
+ this.clients.forEach(function(client){
+ client.websocket.send(name+"@"+doc)
+ })
+ if(callback) callback(false)
+}
+
+
+SynchronizedText.prototype.get = function(callback) {
+ if(callback) callback(false,this.doc)
+}
+
+
+SynchronizedText.prototype.open = function(websocket,callback) {
+ var $this = this
+ , listener = function(msg) {
+ msg = String(msg.data)
+ var index = msg.indexOf("@")
+ if(index !== -1) {
+ var target = msg.slice(0,index)
+ if(target === $this.name) {
+ var doc = msg.slice(index+1)
+ $this.doc = doc
+ if($this.onupdate) $this.onupdate(doc)
+ }
+ }
+ }
+ this.clients.push({websocket:websocket,listener:listener})
+ websocket.addEventListener("message",listener)
+ if(callback) callback(false)
+}
+
+
+SynchronizedText.prototype.close = function(websocket,callback) {
+ var notFound = true
+ this.clients.forEach(function(client){
+ if(client.websocket === websocket) {
+ notFound = false
+ websocket.removeEventListener(client.listener)
+ }
+ })
+ if(callback) callback(notFound)
+}
View
@@ -0,0 +1,41 @@
+//make an input match a SynchronizedText on the server
+function SyncInput(element,websocket,name) {
+ var sync = new SynchronizedText(name)
+ sync.open(websocket)
+ sync.onupdate = function(doc) {
+ element.disabled = false
+ element.value = doc
+ }
+ element.onkeydown = function(e) {
+ if(!element.disabled) {
+ setTimeout(function() {
+ sync.get(function(err,doc) {
+ if(err) console.error(err)
+ else if(doc !== element.value) sync.save(element.value)
+ })
+ },0)
+ }
+ }
+}
+
+window.addEventListener("load",function(){
+ var connection = new WebSocket("ws://localhost:8888")
+ var input = document.getElementsByTagName("input")[0]
+ connection.onopen = function() {
+ SyncInput(
+ document.getElementsByTagName("textarea")[0]
+ , connection
+ , "textarea"
+ )
+ SyncInput(
+ document.getElementsByTagName("input")[0]
+ , connection
+ , "input"
+ )
+ }
+ var color = new SynchronizedText('input.color')
+ color.open(connection)
+ color.onupdate = function(doc) {
+ input.style.color = doc
+ }
+})
View
@@ -0,0 +1,11 @@
+<html>
+<head>
+<title>Concurrent Editor</title>
+<script src="api.js"></script>
+<script src="client.js"></script>
+</head>
+<body>
+<textarea disabled="true" style="width:100%;height:90%;line-height: 19px;font-size: 18px; vertical-align: top"></textarea>
+<input disabled="true">
+</body>
+</html>
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 9a86038

Please sign in to comment.