Completed JsonYatta. Added IwcConnector

This commit is contained in:
Kevin Jahns
2014-08-02 01:39:30 +02:00
parent b91135157e
commit 8169b17eb4
82 changed files with 5547 additions and 591 deletions

View File

@@ -0,0 +1,94 @@
createIwcConnector = (callback)->
iwcHandler = {}
duiClient = new DUIClient()
#@duiClient = new iwc.Client()
duiClient.connect (intent)=>
console.log "intent received iwc: #{JSON.stringify(intent)}"
console.log "#{JSON.stringify(@iwcHandler)}"
iwcHandler[intent.action]?.map (f)->
setTimeout ()->
f intent
, 0
duiClient.initOK()
root_element = null
received_HB = null
class IwcConnector
constructor: (@engine, @HB, @execution_listener, @yatta)->
@duiClient = duiClient
@iwcHandler = iwcHandler
send_ = (o)=>
@send o
@execution_listener.push send_
receive_ = (intent)=>
o = intent.extras
@receive o
@iwcHandler["Yatta_new_operation"] = [receive_]
if root_element?
@engine.applyOps received_HB
sendRootElement = ()=>
json = {
root_element : @yatta.getRootElement()
HB : @yatta.getHistoryBuffer().toJson()
}
@sendIwcIntent "Yatta_push_root_element", json
@iwcHandler["Yatta_get_root_element"] = [sendRootElement]
getRootElement: ()->
root_element
send: (o)->
if o.uid.creator is @HB.getUserId() and (typeof o.uid.op_number isnt "string")
@sendIwcIntent "Yatta_new_operation", o
receive: (o)->
if o.uid.creator isnt @HB.getUserId()
@engine.applyOp o
sendIwcIntent: (action_name, content)->
intent =
action: action_name
component: ""
data: ""
dataType: ""
extras: content
@duiClient.publishToUser(intent)
sync: ()->
throw new Error "Can't use this a.t.m."
get_root_intent =
action: "Yatta_get_root_element"
component: ""
data: ""
dataType: ""
extras: {}
init = ()->
duiClient.publishToUser(get_root_intent)
is_initialized = false
receiveRootElement = (json)->
root_element = json?.extras.root_element
received_HB = json?.extras.HB
if not is_initialized
is_initialized = true
callback IwcConnector
iwcHandler["Yatta_push_root_element"] = [receiveRootElement]
setTimeout receiveRootElement, 3000
setTimeout init, 10
undefined
module.exports = createIwcConnector
window?.createIwcConnector = createIwcConnector

View File

@@ -8,27 +8,26 @@ module.exports = (user_list)->
@send o
@execution_listener.push send_
@applied_operations = []
appliedOperationsListener = (o)=>
@applied_operations.push o
@execution_listener.push appliedOperationsListener
if not (user_list?.length is 0)
@engine.applyOps user_list[0].getHistoryBuffer().toJson()
@unexecuted = {}
@applied_operations = []
appliedOperationsListener = (o)=>
@applied_operations.push o
@execution_listener.push appliedOperationsListener
getOpsInExecutionOrder: ()->
@applied_operations
getRootElement: ()->
if user_list.length > 0
user_list[0].getRootElement()
user_list[0].getRootElement().getUid()
send: (o)->
if o.creator is @HB.getUserId()
if (o.uid.creator is @HB.getUserId()) and (typeof o.uid.op_number isnt "string")
for user in user_list
if not user.getUserId() is @HB.getUserId()
if user.getUserId() isnt @HB.getUserId()
user.getConnector().receive(o)
receive: (o)->
@@ -43,9 +42,8 @@ module.exports = (user_list)->
@flushOne (_.random 0, (user_list.length-1))
flushAll: ()->
for ops of @unexecuted
for n,ops of @unexecuted
@engine.applyOps ops
@unexecuted = {}
sync: ()->
throw new Error "Can't use this a.t.m."

View File

@@ -1,4 +1,3 @@
_ = require "underscore"
class Engine
constructor: (@HB, @parser)->
@@ -12,21 +11,37 @@ class Engine
throw new Error "You forgot to specify a parser for type #{json.type}. The message is #{JSON.stringify json}."
# TODO:
applyOps: (ops)->
applyOps: (ops_json)->
ops = []
for o in ops_json
ops.push @parseOperation o
for o in ops
@applyOp o
@HB.addOperation o
for o in ops
if not o.execute()
@unprocessed_ops.push o
@cleanUp()
cleanUp: ()->
while true
old_length = @unprocessed_ops.length
unprocessed = []
for op in @unprocessed_ops
if not op.execute()
unprocessed.push op
@unprocessed_ops = unprocessed
if @unprocessed_ops.length is old_length
break
applyOp: (op_json)->
# $parse_and_execute will return false if $o_json was parsed and executed, otherwise the parsed operadion
o = @parseOperation o_json
o = @parseOperation op_json
@HB.addOperation o
if not o.execute()
@unprocessed_ops.push o
unprocessed = []
for op in @unprocessed_ops
if not op.execute()
unprocessed.push op
@unprocessed_ops = unprocessed
@cleanUp()
module.exports = Engine

View File

@@ -0,0 +1,40 @@
json_types_uninitialized = require "../Types/JsonTypes.coffee"
HistoryBuffer = require "../HistoryBuffer.coffee"
Engine = require "../Engine.coffee"
class JsonYatta
constructor: (user_id, Connector)->
@HB = new HistoryBuffer user_id
json_types = json_types_uninitialized @HB
@engine = new Engine @HB, json_types.parser
@connector = new Connector @engine, @HB, json_types.execution_listener, @
root_elem = @connector.getRootElement()
if not root_elem?
first_word = new json_types.types.JsonType @HB.getNextOperationIdentifier()
@HB.addOperation(first_word)
first_word.execute()
@root_element = first_word
else
@root_element = @HB.getOperation(root_elem)
getRootElement: ()->
@root_element
getEngine: ()->
@engine
getConnector: ()->
@connector
getHistoryBuffer: ()->
@HB
getUserId: ()->
@HB.getUserId()
val: (name, content)->
@root_element.val(name, content)
window?.JsonYatta = JsonYatta
module.exports = JsonYatta

View File

@@ -9,12 +9,14 @@ class TextYatta
text_types = text_types_uninitialized @HB
@engine = new Engine @HB, text_types.parser
@connector = new Connector @engine, @HB, text_types.execution_listener
@root_element = @connector.getRootElement()
if not @root_element?
root_elem = @connector.getRootElement()
if not root_elem?
first_word = new text_types.types.Word @HB.getNextOperationIdentifier()
@HB.addOperation(first_word)
first_word.execute()
@root_element = @HB.addOperation(new text_types.types.ReplaceManager first_word, @HB.getNextOperationIdentifier()).execute()
else
@root_element = @HB.getOperation(root_elem)
getRootElement: ()->
@root_element

View File

@@ -1,4 +1,3 @@
_ = require "underscore"
#
# An object that holds all applied operations.
@@ -22,13 +21,17 @@ class HistoryBuffer
@user_id
getOperationCounter: ()->
_.clone @operation_counter
res = {}
for user,ctn of @operation_counter
res[user] = ctn
res
toJson: ()->
json = []
for user in @buffer
for o of user
json.push o.toJson()
for u_name,user of @buffer
for o_number,o of user
if not isNaN(parseInt(o_number))
json.push o.toJson()
json
# Get the number of operations that were created by a user.
@@ -51,6 +54,7 @@ class HistoryBuffer
getOperation: (uid)->
if uid instanceof Object
@buffer[uid.creator]?[uid.op_number]
else if not uid?
else
throw new Error "This type of uid is not defined!"
@@ -70,6 +74,4 @@ class HistoryBuffer
@operation_counter[o.creator]++
o
module.exports = HistoryBuffer

View File

@@ -16,6 +16,7 @@ module.exports = (HB)->
{ 'creator': @creator, 'op_number': @op_number }
execute: ()->
@is_executed = true
for l in execution_listener
l @toJson()
@
@@ -62,7 +63,7 @@ module.exports = (HB)->
if op
@[name] = op
else
uninstantiated[name] = op
uninstantiated[name] = op_uid
success = false
delete @unchecked
if not success
@@ -102,7 +103,7 @@ module.exports = (HB)->
# Define how to parse $Delete operations.
#
parser['Delete'] = ({'uid' : uid, 'deletes': deletes_uid})->
new D uid, deletes_uid
new Delete uid, deletes_uid
#
# A simple insert-type operation.
@@ -114,7 +115,6 @@ module.exports = (HB)->
# - The complete-list (abbrev. cl) maintains all operations
#
class Insert extends Operation
# @param {Value} content The value of the insert operation. E.g. for strings content is a char.
# @param {Object} creator A unique user identifier
# @param {Integer} op_number This Number was assigned via getNextOperationIdentifier().
# @param {Operation} prev_cl The predecessor of this operation in the complete-list (cl)
@@ -150,6 +150,9 @@ module.exports = (HB)->
if @origin is o
break
d++
#TODO: delete this
if @ is @prev_cl
throw new Error "this should not happen ;) "
o = o.prev_cl
d
@@ -175,10 +178,12 @@ module.exports = (HB)->
# Include this operation in the associative lists.
#
execute: ()->
if @is_executed?
return @
if not @validateSavedOperations()
return false
else
if @prev_cl? and @next_cl?
if @prev_cl?.validateSavedOperations() and @next_cl?.validateSavedOperations() and @prev_cl.next_cl isnt @
distance_to_origin = 0
o = @prev_cl.next_cl
i = 0
@@ -247,17 +252,19 @@ module.exports = (HB)->
0
execute: ()->
a = @validateSavedOperations()
for l in execution_listener
l @toJson()
a
if @validateSavedOperations()
for l in execution_listener
l @toJson()
@
else
false
toJson: ()->
{
'type' : "Delimiter"
'uid' : @getUid()
'prev' : @prev_cl.getUid()
'next' : @next_cl.getUid()
'prev' : @prev_cl?.getUid()
'next' : @next_cl?.getUid()
}
parser['Delimiter'] = (json)->

View File

@@ -0,0 +1,49 @@
text_types_uninitialized = require "./TextTypes.coffee"
module.exports = (HB)->
text_types = text_types_uninitialized HB
types = text_types.types
parser = text_types.parser
class JsonType extends types.MapManager
constructor: (uid, initial_value)->
super uid
if initial_value?
if typeof initial_value isnt "object"
throw new Error "The initial value of JsonTypes must be of type Object! (current type: #{typeof initial_value})"
for name,o of initial_value
@val name, o
val: (name, content)->
if name? and content?
if typeof content is 'string'
word = HB.addOperation(new types.Word HB.getNextOperationIdentifier(), content).execute()
super name, word
content
else if typeof content is 'object'
json = HB.addOperation(JsonType HB.getNextOperationIdentifier(), content).execute()
super name, json
content
else
throw new Error "You must not set #{typeof content}-types in collaborative Json-objects!"
else
super name, content
toJson: ()->
{
'type' : "JsonType"
'uid' : @getUid()
}
parser['JsonType'] = (json)->
{
'uid' : uid
} = json
new JsonType uid
types['JsonType'] = JsonType
text_types

View File

@@ -1,4 +1,3 @@
_ = require "underscore"
basic_types_uninitialized = require "./BasicTypes.coffee"
module.exports = (HB)->
@@ -6,24 +5,75 @@ module.exports = (HB)->
types = basic_types.types
parser = basic_types.parser
class MapManager
constructor: ()->
class MapManager extends types.Operation
constructor: (uid)->
@map = {}
super uid
set: (name, content)->
if not @map[name]?
@map[name] = new Replaceable HB,
val: (name, content)->
if content?
if not @map[name]?
HB.addOperation(new AddName HB.getNextOperationIdentifier(), @, name).execute()
@map[name].replace content
else if name?
@map[name]?.val()
else
result = {}
for name,o of @map
result[name] = o.val()
result
class AddName extends types.Operation
constructor: (uid, map_manager, @name)->
@saveOperation 'map_manager', map_manager
super uid
execute: ()->
if not @validateSavedOperations()
return false
else
uid_r = @map_manager.getUid()
uid_r.op_number = "_#{uid_r.op_number}_RM_#{@name}"
if not HB.getOperation(uid_r)?
uid_beg = @map_manager.getUid()
uid_beg.op_number = "_#{uid_beg.op_number}_RM_#{@name}_beginning"
uid_end = @map_manager.getUid()
uid_end.op_number = "_#{uid_end.op_number}_RM_#{@name}_end"
beg = HB.addOperation(new types.Delimiter uid_beg, undefined, uid_end)
end = HB.addOperation(new types.Delimiter uid_end, beg, undefined).execute()
beg.execute()
@map_manager.map[@name] = HB.addOperation(new ReplaceManager undefined, uid_r, beg, end).execute()
super
toJson: ()->
{
'type' : "AddName"
'uid' : @getUid()
'map_manager' : @map_manager.getUid()
'name' : @name
}
parser['AddName'] = (json)->
{
'map_manager' : map_manager
'uid' : uid
'name' : name
} = json
new AddName uid, map_manager, name
class ListManager extends types.Insert
constructor: (uid, beginning, end, prev, next, origin)->
if beginning? and end?
saveOperation "beginning", beginning
saveOperation "end", end
@saveOperation 'beginning', beginning
@saveOperation 'end', end
else
@beginning = HB.addOperation new types.Delimiter HB.getNextOperationIdentifier(), undefined, undefined
@end = HB.addOperation new types.Delimiter HB.getNextOperationIdentifier(), @beginning, undefined
@beginning.next_cl = @end
@beginning.execute()
@end.execute()
super uid, prev, next, origin
# Get the element previous to the delemiter at the end
@@ -83,8 +133,8 @@ module.exports = (HB)->
{
'type': "ReplaceManager"
'uid' : @getUid()
'beginning' : @beginning
'end' : @end
'beginning' : @beginning.getUid()
'end' : @end.getUid()
}
if @prev_cl? and @next_cl?
json['prev'] = @prev_cl.getUid()
@@ -113,8 +163,8 @@ module.exports = (HB)->
constructor: (content, parent, uid, prev, next, origin)->
@saveOperation 'content', content
@saveOperation 'parent', parent
if not (prev? and next?)
throw new Error "You must define prev, and next for Replaceable-types!"
if not (prev? and next? and content?)
throw new Error "You must define content, prev, and next for Replaceable-types!"
super uid, prev, next, origin
#
@@ -126,9 +176,12 @@ module.exports = (HB)->
@parent.replace content
execute: ()->
super
@content.setReplaceManager?(@parent)
@
if not @validateSavedOperations()
return false
else
@content.setReplaceManager?(@parent)
super
@
#
# Convert all relevant information of this operation to the json-format.
@@ -139,7 +192,7 @@ module.exports = (HB)->
{
'type': "Replaceable"
'content': @content.getUid()
'ReplaceManager' : @parent
'ReplaceManager' : @parent.getUid()
'prev': @prev_cl.getUid()
'next': @next_cl.getUid()
'uid' : @getUid()

View File

@@ -1,4 +1,3 @@
_ = require "underscore"
structured_types_uninitialized = require "./StructuredTypes.coffee"
module.exports = (HB)->
@@ -69,8 +68,10 @@ module.exports = (HB)->
new TextInsert content, uid, prev, next, origin
class Word extends types.ListManager
constructor: (uid, prev, next, origin)->
super uid, prev, next, origin
constructor: (uid, initial_content, beginning, end, prev, next, origin)->
super uid, beginning, end, prev, next, origin
if initial_content?
@insertText 0, initial_content
# inserts a
insertText: (position, content)->
@@ -114,9 +115,10 @@ module.exports = (HB)->
toJson: ()->
json = {
'type': "TextInsert"
'content': @content
'type': "Word"
'uid' : @getUid()
'beginning' : @beginning.getUid()
'end' : @end.getUid()
}
if @prev_cl?
json['prev'] = @prev_cl.getUid()
@@ -128,13 +130,14 @@ module.exports = (HB)->
parser['Word'] = (json)->
{
'content' : content
'uid' : uid
'beginning' : beginning
'end' : end
'prev': prev
'next': next
'origin' : origin
} = json
new Word uid, prev, next, origin
new Word uid, undefined, beginning, end, prev, next, origin
types['TextInsert'] = TextInsert
types['TextDelete'] = TextDelete

View File

@@ -1 +0,0 @@
_ = require "underscore"