improved sync process (HB._encode)
This commit is contained in:
@@ -13,7 +13,6 @@ createIwcConnector = (callback)->
|
||||
|
||||
duiClient.initOK()
|
||||
|
||||
root_element = null
|
||||
received_HB = null
|
||||
|
||||
#
|
||||
@@ -35,19 +34,15 @@ createIwcConnector = (callback)->
|
||||
@receive o
|
||||
@iwcHandler["Yatta_new_operation"] = [receive_]
|
||||
|
||||
if root_element?
|
||||
@engine.applyOps received_HB
|
||||
if received_HB?
|
||||
@engine.applyOpsCheckDouble received_HB
|
||||
|
||||
sendRootElement = ()=>
|
||||
sendHistoryBuffer = ()=>
|
||||
json = {
|
||||
root_element : @yatta.getRootElement()
|
||||
HB : @yatta.getHistoryBuffer()._encode()
|
||||
}
|
||||
@sendIwcIntent "Yatta_push_root_element", json
|
||||
@iwcHandler["Yatta_get_root_element"] = [sendRootElement]
|
||||
|
||||
getRootElement: ()->
|
||||
root_element
|
||||
@sendIwcIntent "Yatta_push_HB_element", json
|
||||
@iwcHandler["Yatta_get_HB_element"] = [sendHistoryBuffer]
|
||||
|
||||
send: (o)->
|
||||
if o.uid.creator is @HB.getUserId() and (typeof o.uid.op_number isnt "string")
|
||||
@@ -70,28 +65,27 @@ createIwcConnector = (callback)->
|
||||
sync: ()->
|
||||
throw new Error "Can't use this a.t.m."
|
||||
|
||||
get_root_intent =
|
||||
action: "Yatta_get_root_element"
|
||||
get_HB_intent =
|
||||
action: "Yatta_get_HB_element"
|
||||
component: ""
|
||||
data: ""
|
||||
dataType: ""
|
||||
extras: {}
|
||||
|
||||
init = ()->
|
||||
duiClient.sendIntent(get_root_intent)
|
||||
duiClient.sendIntent(get_HB_intent)
|
||||
|
||||
is_initialized = false
|
||||
receiveRootElement = (json)->
|
||||
receiveHB = (json)->
|
||||
proposed_user_id = duiClient.getIwcClient()._componentName
|
||||
root_element = json?.extras.root_element
|
||||
received_HB = json?.extras.HB
|
||||
if not is_initialized
|
||||
is_initialized = true
|
||||
callback IwcConnector, proposed_user_id
|
||||
iwcHandler["Yatta_push_root_element"] = [receiveRootElement]
|
||||
setTimeout receiveRootElement, 800
|
||||
iwcHandler["Yatta_push_HB_element"] = [receiveHB]
|
||||
setTimeout receiveHB, 0
|
||||
|
||||
setTimeout init, (Math.random()*4000)
|
||||
setTimeout init, (Math.random()*0)
|
||||
|
||||
undefined
|
||||
module.exports = createIwcConnector
|
||||
|
||||
@@ -24,10 +24,6 @@ module.exports = (user_list)->
|
||||
getOpsInExecutionOrder: ()->
|
||||
@applied_operations
|
||||
|
||||
getRootElement: ()->
|
||||
if user_list.length > 0
|
||||
user_list[0].getRootElement().getUid()
|
||||
|
||||
send: (o)->
|
||||
if (o.uid.creator is @HB.getUserId()) and (typeof o.uid.op_number isnt "string")
|
||||
for user in user_list
|
||||
|
||||
@@ -6,6 +6,9 @@ class Engine
|
||||
constructor: (@HB, @parser)->
|
||||
@unprocessed_ops = []
|
||||
|
||||
#
|
||||
# Parses an operatio from the json format. It uses the specified parser in your OperationType module.
|
||||
#
|
||||
parseOperation: (json)->
|
||||
typeParser = @parser[json.type]
|
||||
if typeParser?
|
||||
@@ -13,10 +16,11 @@ class Engine
|
||||
else
|
||||
throw new Error "You forgot to specify a parser for type #{json.type}. The message is #{JSON.stringify json}."
|
||||
|
||||
applyOps: (ops_json)->
|
||||
for o in ops_json
|
||||
@applyOp o
|
||||
###
|
||||
#
|
||||
# Apply a set of operations. E.g. the operations you received from another users HB.toJson().
|
||||
# @note You must not use this method when you already have ops in your HB!
|
||||
#
|
||||
applyOpsBundle: (ops_json)->
|
||||
ops = []
|
||||
for o in ops_json
|
||||
ops.push @parseOperation o
|
||||
@@ -26,15 +30,36 @@ class Engine
|
||||
if not o.execute()
|
||||
@unprocessed_ops.push o
|
||||
@tryUnprocessed()
|
||||
###
|
||||
|
||||
applyOpsCheckDouble: (ops_json)->
|
||||
for o in ops_json
|
||||
if @HB.getOperation(o.uid)?
|
||||
@applyOp o
|
||||
|
||||
#
|
||||
# Apply a set of operations. (Helper for using applyOp on Arrays)
|
||||
# @see Engine.applyOp
|
||||
applyOps: (ops_json)->
|
||||
for o in ops_json
|
||||
@applyOp o
|
||||
|
||||
#
|
||||
# Apply an operation that you received from another peer.
|
||||
#
|
||||
applyOp: (op_json)->
|
||||
# $parse_and_execute will return false if $o_json was parsed and executed, otherwise the parsed operadion
|
||||
o = @parseOperation op_json
|
||||
@HB.addOperation o
|
||||
# @HB.addOperation o
|
||||
if not o.execute()
|
||||
@unprocessed_ops.push o
|
||||
else
|
||||
@HB.addOperation o
|
||||
@tryUnprocessed()
|
||||
|
||||
#
|
||||
# Call this method when you applied a new operation.
|
||||
# It checks if operations that were previously not executable are now executable.
|
||||
#
|
||||
tryUnprocessed: ()->
|
||||
while true
|
||||
old_length = @unprocessed_ops.length
|
||||
@@ -42,6 +67,8 @@ class Engine
|
||||
for op in @unprocessed_ops
|
||||
if not op.execute()
|
||||
unprocessed.push op
|
||||
else
|
||||
@HB.addOperation op
|
||||
@unprocessed_ops = unprocessed
|
||||
if @unprocessed_ops.length is old_length
|
||||
break
|
||||
|
||||
@@ -42,12 +42,29 @@ class HistoryBuffer
|
||||
res[user] = ctn
|
||||
res
|
||||
|
||||
_encode: ()->
|
||||
_encode: (state_vector={})->
|
||||
json = []
|
||||
unknown = (user, o_number)->
|
||||
if (not user?) or (not o_number?)
|
||||
throw new Error "dah!"
|
||||
not state_vector[user]? or state_vector[user] <= o_number
|
||||
|
||||
for u_name,user of @buffer
|
||||
for o_number,o of user
|
||||
if not isNaN(parseInt(o_number))
|
||||
json.push o._encode()
|
||||
if not isNaN(parseInt(o_number)) and unknown(u_name, o_number)
|
||||
o_json = o._encode()
|
||||
if o.next_cl?
|
||||
o_next = o.next_cl
|
||||
while o_next.next_cl? and unknown(o_next.creator, o_next.op_number)
|
||||
o_next = o_next.next_cl
|
||||
o_json.next = o_next.getUid()
|
||||
else if o.prev_cl?
|
||||
o_prev = o.prev_cl
|
||||
while o_prev.prev_cl? and unknown(o_next.creator, o_next.op_number)
|
||||
o_prev = o_prev.prev_cl
|
||||
o_json.prev = o_prev.getUid()
|
||||
json.push o_json
|
||||
|
||||
json
|
||||
|
||||
#
|
||||
|
||||
@@ -332,18 +332,48 @@ module.exports = (HB)->
|
||||
# This is necessary in order to have a beginning and an end even if the content
|
||||
# of the Engine is empty.
|
||||
#
|
||||
class Delimiter extends Insert
|
||||
class Delimiter extends Operation
|
||||
#
|
||||
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
|
||||
# @param {Operation} prev_cl The predecessor of this operation in the complete-list (cl)
|
||||
# @param {Operation} next_cl The successor of this operation in the complete-list (cl)
|
||||
#
|
||||
# @see HistoryBuffer.getNextOperationIdentifier
|
||||
#
|
||||
constructor: (uid, prev_cl, next_cl, origin)->
|
||||
@saveOperation 'prev_cl', prev_cl
|
||||
@saveOperation 'next_cl', next_cl
|
||||
@saveOperation 'origin', prev_cl
|
||||
super uid
|
||||
|
||||
#
|
||||
# If isDeleted() is true this operation won't be maintained in the sl
|
||||
#
|
||||
isDeleted: ()->
|
||||
false
|
||||
|
||||
#
|
||||
# @private
|
||||
#
|
||||
execute: ()->
|
||||
if @validateSavedOperations()
|
||||
for l in execution_listener
|
||||
l @_encode()
|
||||
@
|
||||
if @unchecked?['next_cl']?
|
||||
super
|
||||
else if @unchecked?['prev_cl']
|
||||
if @validateSavedOperations()
|
||||
if @prev_cl.next_cl?
|
||||
throw new Error "Probably duplicated operations"
|
||||
@prev_cl.next_cl = @
|
||||
delete @prev_cl.unchecked.next_cl
|
||||
super
|
||||
else
|
||||
false
|
||||
else if @prev_cl? and not @prev_cl.next_cl?
|
||||
delete @prev_cl.unchecked.next_cl
|
||||
@prev_cl.next_cl = @
|
||||
else if @prev_cl? or @next_cl?
|
||||
super
|
||||
else
|
||||
false
|
||||
throw new Error "Delimiter is unsufficient defined!"
|
||||
|
||||
#
|
||||
# @private
|
||||
|
||||
@@ -66,9 +66,9 @@ module.exports = (HB)->
|
||||
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)
|
||||
beg = HB.addOperation(new types.Delimiter uid_beg, undefined, uid_end).execute()
|
||||
end = HB.addOperation(new types.Delimiter uid_end, beg, undefined).execute()
|
||||
beg.execute()
|
||||
#beg.execute()
|
||||
@map_manager.map[@name] = HB.addOperation(new ReplaceManager undefined, uid_r, beg, end).execute()
|
||||
super
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ module.exports = (HB)->
|
||||
o = @getOperationByPosition position
|
||||
|
||||
for i in [0...length]
|
||||
d = HB.addOperation(new TextDelete HB.getNextOperationIdentifier(), o).execute()
|
||||
d = HB.addOperation(new TextDelete undefined, o).execute()
|
||||
o = o.next_cl
|
||||
while o.isDeleted()
|
||||
if o instanceof types.Delimiter
|
||||
@@ -115,7 +115,7 @@ module.exports = (HB)->
|
||||
#
|
||||
replaceText: (text)->
|
||||
if @replace_manager?
|
||||
word = HB.addOperation(new Word HB.getNextOperationIdentifier()).execute()
|
||||
word = HB.addOperation(new Word undefined).execute()
|
||||
word.insertText 0, text
|
||||
@replace_manager.replace(word)
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user