lib/africompta/entities/remote.rb in africompta-1.9.10 vs lib/africompta/entities/remote.rb in africompta-1.9.11
- old
+ new
@@ -1,27 +1,261 @@
class Remotes < Entities
-
- def create( d )
- r = super( d )
- d.has_key?( :account_index ) || r.account_index = 0
- d.has_key?( :movement_index ) || r.movement_index = 0
+
+ def create(d)
+ r = super(d)
+ d.has_key?(:account_index) || r.account_index = 0
+ d.has_key?(:movement_index) || r.movement_index = 0
r
end
-
+
def setup_data
value_str :url
value_str :name
value_str :pass
value_int :account_index
value_int :movement_index
end
+
+ def self.get_db(url, name, pass)
+ vers = Net::HTTP.get(URI.parse("#{url}/merge/version/#{name},#{pass}"))
+ if vers != $VERSION.to_s
+ return (vers =~ /not known/) ? 'User and/or password wrong' : 'Version mismatch'
+ end
+
+ db = Net::HTTP.get(URI.parse("#{url}/merge/get_db/#{name},#{pass}"))
+
+ SQLite.dbs_close_all
+ # All accounting-stuff is stored in the same database
+ IO.write(Accounts.storage[:SQLiteAC].db_file, db)
+ IO.write('/tmp/compta.db', db)
+ SQLite.dbs_open_load_migrate
+
+ # Delete all users except for the 'local' who needs a new id
+ Users.search_all_.each { |u|
+ if u.name == 'local'
+ u.reset_id
+ else
+ u.delete
+ end
+ }
+
+ # Delete all other remotes and add ourselves
+ Remotes.search_all_.each { |r| r.delete }
+ remote = Remotes.create(url: url, name: name, pass: pass)
+
+ # Update all indexes
+ ret = remote.do_copied
+ if ret == true
+ remote
+ else
+ ret
+ end
+ end
end
class Remote < Entity
+ attr_reader :step, :got_accounts, :put_accounts, :got_movements,
+ :put_movements, :put_movements_changes
+
+ def setup_instance
+ u = Users.find_by_name('local')
+ @step = 'preparation'
+ @account_index_stop, @movement_index_stop,
+ @got_accounts, @put_accounts,
+ @got_movements, @put_movements, @put_movements_changes =
+ [0] * 7
+ @account_index_stop = u.account_index - 1
+ @movement_index_stop = u.movement_index - 1
+ end
+
def update_movement_index
self.movement_index = Users.match_by_name('local').movement_index - 1
end
def update_account_index
self.account_index = Users.match_by_name('local').account_index - 1
+ end
+
+ def post_form(path, hash)
+ dputs(4) { "Starting postForm with path #{path}" }
+ Net::HTTP.post_form(URI.parse(url + "/merge/#{path}"),
+ {'user' => name, 'pass' => pass}.merge(hash))
+ dputs(4) { "Ending postForm with path #{path}" }
+ end
+
+ def get_form(path)
+ url_parsed = URI.parse(url)
+ dputs(4) { "Starting getForm with path #{path} - #{url_parsed.inspect}" }
+ dputs(4) { "Finished parsing #{url}" }
+ ret = Net::HTTP.get(url_parsed.host, "#{url_parsed.path}/merge/#{path}/#{name},#{pass}", url_parsed.port)
+ dputs(4) { "Ending getForm with path #{path}" }
+ ret
+ end
+
+ # Calls the remote end and searches for new accounts and movements
+ # on both sides. Steps:
+ # 0: check version
+ # 1: get remote accounts
+ # 2: send our accounts
+ # 3: get remote movements
+ # 4: send our movements
+ # 5: update the indexes
+ # The variable +step+ can be used to watch the progress if it is called
+ # in a thread
+ def do_merge
+ setup_instance
+
+ u = Users.find_by_name('local')
+ log_msg :Merging, "Starting to merge for #{url}"
+
+ @step = 'checking remote'
+ begin
+ check_version
+ rescue StandardError => e
+ @step = "done - error: #{e.to_s}"
+ return
+ end
+
+ @step = 'getting remote accounts'
+ get_remote_accounts
+
+ @step = 'sending our accounts'
+ send_accounts
+
+ @step = 'getting remote movements'
+ get_remote_movements
+
+ @step = 'sending movements'
+ send_movements
+
+ @step = 'updating all indexes'
+ # Update the pointer
+ update_movement_index
+ # Update the remote pointers
+ get_form('reset_user_indexes')
+
+ @step = 'done'
+ end
+
+ def check_version(show_error = true)
+ local_id = Users.find_by_name('local').full
+ dputs(2) { "Local id is: #{local_id}" }
+ if (local_id == get_form('local_id'))
+ show_error and dputs(0) { 'Both locals have same ID' }
+ raise 'Same ID for local'
+ end
+
+ # Check the versions
+ if (vers = get_form('version')) != $VERSION.to_s
+ if (vers =~ /not known/)
+ show_error and dputs(0) { 'Username / password not recognized' }
+ raise 'Wrong credentials'
+ else
+ show_error and dputs(0) { "Got version #{vers} instead of #{$VERSION.to_s}" }
+ raise 'Wrong version'
+ end
+ end
+ return true
+ end
+
+ def get_remote_accounts
+ dputs(2) { 'Getting remotes' }
+ accounts = get_form('accounts_get')
+ accounts.split("\n").each { |a|
+ acc = Accounts.from_s(a)
+ dputs(2) { "Got account #{acc.name}" }
+ @got_accounts += 1
+ }
+ end
+
+ def send_accounts
+ @account_index_start = account_index.to_i + 1
+ if @account_index_start <= @account_index_stop
+ dputs(1) { "Accounts to send: #{@account_index_start}..#{@account_index_stop}" }
+ # Just search all accounts for indexes and sort them
+ Accounts.data.select { |k, v|
+ v._rev_index.between?(@account_index_start, @account_index_stop)
+ }.collect { |k, v| Accounts.get_data_instance(k) }.
+ sort_by { |a| a.rev_index }.each { |acc|
+ dputs(2) { "Account with index #{acc.rev_index} is being transferred" }
+ post_form('account_put', {'account' => acc.to_s})
+ @put_accounts += 1
+
+ }
+ else
+ dputs(1) { 'No accounts to send' }
+ end
+ # Update the pointer
+ update_account_index
+ end
+
+ def get_remote_movements
+ dputs(1) { 'Getting movements' }
+ # Now merge the movements
+ movements = get_form('movements_get')
+ movements.split("\n").each { |m|
+ dputs(2) { "String is: \n#{m}" }
+ mov = Movements.from_s(m)
+ @got_movements += 1
+ }
+ end
+
+ def send_movements
+ #dputs_func
+ @movement_index_start = movement_index.to_i + 1
+ @movement_count = 0
+ if @movement_index_start <= @movement_index_stop
+ dputs(1) { "Movements to send: #{@movement_index_start}.." +
+ "#{@movement_index_stop}" }
+ movements = []
+ Movements.data.select { |k, v| v._rev_index.between?(
+ @movement_index_start, @movement_index_stop
+ ) }.each { |k, v|
+ m = Movements.get_data_instance(k)
+ movements.push(m.to_json)
+ @put_movements += 1
+ }
+ @movement_count = movements.size
+ dputs(1) { "Having #{movements.size} movements to send" }
+ while movements.size > 0
+ # We'll do it by bunches of 10
+ movements_put = movements.shift 10
+ dputs(1) { 'Putting one bunch of 10 movements' }
+ dputs(4) { movements_put.to_json }
+ post_form('movements_put', {'movements' => movements_put.to_json})
+ @put_movements_changes += 1
+ # TODO: remove
+ # movements = []
+ end
+ else
+ dputs(1) { 'No movements to send' }
+ end
+ end
+
+ # Is used to reset the pointers, supposes both databases are equal -
+ # Should probably be used with care
+ def do_copied
+ check_version
+
+ # Update local indexes
+ u = Users.find_by_name('local')
+ update_account_index
+ update_movement_index
+
+ # Update remote indexes
+ get_form('reset_user_indexes')
+
+ # Check if everything is OK
+ acc, mov = get_form('index').split(',')
+
+ if acc.to_i != u.account_index
+ dputs(0) { "Trying to do 'copied' with wrong account-indexes" }
+ dputs(0) { "#{acc.to_i} - #{u.account_index}" }
+ end
+ if mov.to_i != u.movement_index
+ dputs(0) { "Trying to do 'copied' with wrong movement-indexes" }
+ dputs(0) { "#{mov.to_i} - #{u.movement_index}" }
+ end
+
+ return true
end
end