class DaFunk::Transaction::Download

Constants

COMMUNICATION_ERROR
ERL_ATOM_EXT
ERL_BINARY_EXT
ERL_CONTENT_TYPE
ERL_INTEGER_EXT
ERL_NIL_EXT
ERL_SMALL_TUPLE_EXT
ERL_VERSION_MAGIC
FILE_NOT_CHANGE
FILE_NOT_FOUND
IO_ERROR
MAPREDUCE_RESPONSE_ERROR
MAXATOMLEN
PARAMS_FILE
SERIAL_NUMBER_NOT_FOUND
SUCCESS

Attributes

buffer[RW]
crc[RW]
first_packet[RW]
path[RW]
request[RW]
socket[RW]

Public Class Methods

check(ret) click to toggle source
# File lib/da_funk/transaction/download.rb, line 23
def self.check(ret)
  case ret
  when SERIAL_NUMBER_NOT_FOUND
  when FILE_NOT_FOUND
  when FILE_NOT_CHANGE
    return true
  when SUCCESS
    return true
  when COMMUNICATION_ERROR
  when MAPREDUCE_RESPONSE_ERROR
  when IO_ERROR
  end
  false
end
new(serial, path, version) click to toggle source
# File lib/da_funk/transaction/download.rb, line 52
def initialize(serial, path, version)
  @serial  = serial
  @path    = path
  @version = version
end
request_file(remote_path, local_path, crc = nil) click to toggle source
# File lib/da_funk/transaction/download.rb, line 38
def self.request_file(remote_path, local_path, crc = nil)
  download = DaFunk::Transaction::Download.new(Device::System.serial, "", DaFunk::VERSION)
  download.perform(Device::Network.socket,
                   Device::Setting.company_name,
                   remote_path, local_path, Device::System.app,
                   Device::Setting.logical_number, crc)
end
request_param_file(file = PARAMS_FILE) click to toggle source
# File lib/da_funk/transaction/download.rb, line 46
def self.request_param_file(file = PARAMS_FILE)
  request_file("#{Device::Setting.logical_number}_#{PARAMS_FILE}", file)
end

Public Instance Methods

generate_crc(local_path) click to toggle source
# File lib/da_funk/transaction/download.rb, line 141
def generate_crc(local_path)
  if File.exists?(local_path)
    file = File.open(local_path)
    Device::Crypto.crc16_hex(file.read)
  else
    ""
  end
ensure
  file.close if file
end
perform(socket_proc, company_name, remote_path, filepath, current_app, logical_number, file_crc = nil, socket_call = true) click to toggle source
0: Success

-1: Commnucation error -2: Mapreduce response error -3: IO Error

# File lib/da_funk/transaction/download.rb, line 62
def perform(socket_proc, company_name, remote_path, filepath, current_app, logical_number, file_crc = nil, socket_call = true)
  if socket_call
    @socket, @buffer, @request, @first_packet = socket_proc.call, "", "", ""
  else
    @socket, @buffer, @request, @first_packet = socket_proc, "", "", ""
  end
  @crc = file_crc ? file_crc : generate_crc(filepath)
  key = "#{company_name}_#{remote_path}"

  ei_encode_version                # version
  ei_encode_list_header(3)         # mapreduce with 3 tuples
  ei_encode_tuple_header(2)        # tuple 1 inputs
  ei_encode_atom("inputs")         # atom inputs
  ei_encode_list_header(1)         # list inputs
  ei_encode_tuple_header(2)        # tuple contendo 2 elementos binarios, bucket and key
  ei_encode_binary("assets")       # elemento binario bucket
  ei_encode_binary(key)            # elemento binario key
  ei_encode_list_header(0)         # fim da list do inputs

  ei_encode_tuple_header(2)        # tuple 2: query
  ei_encode_atom("query")          # atom query
  ei_encode_list_header(1)         # list da query
  ei_encode_tuple_header(4)        # tuple contendo 4 elementos, { map, {modfun,Module,Function}, args, true }
  ei_encode_atom("map")            # primeiro elemento, atom type
  ei_encode_tuple_header(3)        # segundo elemento, nova tuple contendo 3 atoms
  ei_encode_atom("modfun")         # primeiro atom do segundo elemento, modfun
  ei_encode_atom("walk")           # segundo atom do segundo elemento, Module
  ei_encode_atom("get_asset")      # terceiro atom do segundo elemento, Function

  ei_encode_list_header(7)         # terceiro elemento, uma list com parametros do walk
  ei_encode_binary(@serial)        # elemento binario serialterminal
  ei_encode_binary(@version)       # elemento binario versao walk
  ei_encode_binary(remote_path)      # elemento binario nomeaplicativo
  ei_encode_binary(@crc)            # elemento binario crc aplicativo
  ei_encode_binary("")             # elemento binario buffer do posxml
  ei_encode_binary(logical_number) # elemento binario numero do terminal
  ei_encode_binary(current_app)    # elemento binario nome do aplicativo que esta sendo executado
  ei_encode_list_header(0)         # fim da list com parametros do walk

  ei_encode_atom("true")           # quarto elemento, atom true
  ei_encode_list_header(0)         # fim da list da query

  ei_encode_tuple_header(2)        # tuple 3: timeout
  ei_encode_atom("timeout")        # atom timeout
  ei_encode_long(5000)             # integer timeout
  ei_encode_list_header(0)         # fim da list do mapreduce contendo 3 tuples

  mount_request                    # add request to protocol buffers message

  return COMMUNICATION_ERROR unless @socket

  # Send Request
  socket.write(@request)

  return COMMUNICATION_ERROR if (response_size = get_response_size(read_header_size(socket))) <= 0

  return MAPREDUCE_RESPONSE_ERROR unless @first_packet = get_binary_term_beginning(response_size)

  return_code = @first_packet[7].to_s.unpack("C*").first
  file_size   = @first_packet[9..12].to_s.unpack("N*").first

  if return_code != FILE_NOT_CHANGE
    return IO_ERROR if (partial_download_to_store(filepath, response_size, file_size) < 0)
  end

  # receive 6A
  @socket.read(1) if response_size > 1024
  if socket_call
    @socket.close unless @socket.closed?
  end

  return_code
rescue SocketError
  return COMMUNICATION_ERROR
rescue => e
  ContextLog.exception(e, e.backtrace)
  return IO_ERROR
end

Private Instance Methods

ei_encode_atom(value) click to toggle source

TODO: Check why MAXATOMLEN

# File lib/da_funk/transaction/download.rb, line 270
def ei_encode_atom(value)
  value.size > MAXATOMLEN ? len = MAXATOMLEN : len = value.size
  put8(ERL_ATOM_EXT)
  put16be(len)
  put(value)
end
ei_encode_binary(value) click to toggle source
# File lib/da_funk/transaction/download.rb, line 277
def ei_encode_binary(value)
  put8(ERL_BINARY_EXT)

  # TODO: Check it after to implement on put.
  if value.is_a? Fixnum
    put32be(2)
    @buffer << [value].pack("s")
  else
    put32be(value.size)
    put(value)
  end
end
ei_encode_list_header(arity) click to toggle source
# File lib/da_funk/transaction/download.rb, line 258
def ei_encode_list_header(arity)
  put8(ERL_NIL_EXT)
  put32be(arity) if arity > 0
end
ei_encode_long(value) click to toggle source
# File lib/da_funk/transaction/download.rb, line 290
def ei_encode_long(value)
  put8(ERL_INTEGER_EXT)
  put32be(value)
end
ei_encode_tuple_header(arity) click to toggle source
# File lib/da_funk/transaction/download.rb, line 263
def ei_encode_tuple_header(arity)
  # if (arity <= 0xff) ERL_SMALL_TUPLE_EXT else ERL_LARGE_TUPLE_EXT
  put8(ERL_SMALL_TUPLE_EXT)
  put8(arity.chr);
end
ei_encode_version() click to toggle source
# File lib/da_funk/transaction/download.rb, line 254
def ei_encode_version
  put8(ERL_VERSION_MAGIC.chr)
end
get_binary_term_beginning(response_size) click to toggle source
# File lib/da_funk/transaction/download.rb, line 189
def get_binary_term_beginning(response_size)
  if response_size > 1024
    packet = socket.read(1024)
  else
    packet = socket.read(response_size)
  end

  if packet.include?("\x83\x6c\x00")
    "\x83\x6c\x00#{packet.split("\x83\x6C\x00")[1]}"
  else
    return false
  end
end
get_response_size(bytes) click to toggle source
# File lib/da_funk/transaction/download.rb, line 184
def get_response_size(bytes)
  return -1 if bytes.to_s.size <= 0
  bytes.to_s.unpack("N*").first
end
ljust(size, string) click to toggle source

MRuby do not support String#ljust TODO: duplicated from lib/variable.rb

# File lib/da_funk/transaction/download.rb, line 310
def ljust(size, string)
  if size > string.size
    string = string + ("\x00" * (size - string.size))
  end
  string
end
makelong(a, b) click to toggle source
# File lib/da_funk/transaction/download.rb, line 203
def makelong(a, b)
  (a & 0xffff) | ((b & 0xffff) << 16)
end
makeword(a, b) click to toggle source
# File lib/da_funk/transaction/download.rb, line 207
def makeword(a, b)
  (a & 0xff) | ((b & 0xff) << 8)
end
mount_request() click to toggle source
# File lib/da_funk/transaction/download.rb, line 295
def mount_request
  request_size   = [@buffer.size].pack("s") + "\x01"

  put8("\x12")
  put8("\x1b")
  new_request = [@request.size].pack("N")
  new_request << "\x17"
  new_request << "\x0A"
  new_request << "#{request_size}#{@buffer}#{ERL_CONTENT_TYPE}"
  new_request << @request
  @request = new_request
end
partial_download_to_store(filepath, response_size, file_size) click to toggle source
# File lib/da_funk/transaction/download.rb, line 211
def partial_download_to_store(filepath, response_size, file_size)
  tmp  = tmp_file(filepath)
  file = File.open(tmp, "w")

  if (response_size > 1024)
    file.write(@first_packet[13..-1])
    downloaded = 1024
    while(downloaded < (response_size - 1))

      if (to_download = response_size - downloaded) > 1024
        to_download = 1024
      else
        to_download -= 1 # because of 6A
      end

      downloaded += file.write(socket.read(to_download))
    end
  else
    # -2 because of 6A
    downloaded = file.write(@first_packet[13..-2])
  end

  file.close
  File.rename(tmp, filepath)
  downloaded
end
put(value) click to toggle source
# File lib/da_funk/transaction/download.rb, line 238
def put(value)
  @buffer << value
end
put16be(value) click to toggle source
# File lib/da_funk/transaction/download.rb, line 250
def put16be(value)
  @buffer << [value].pack("n")
end
put32be(value) click to toggle source
# File lib/da_funk/transaction/download.rb, line 246
def put32be(value)
  @buffer << [value].pack("N")
end
put8(value) click to toggle source
# File lib/da_funk/transaction/download.rb, line 242
def put8(value)
  @buffer << value
end
read_header_size(socket) click to toggle source
# File lib/da_funk/transaction/download.rb, line 154
def read_header_size(socket)
  buf, error = socket_read(socket, 4, Device::Setting.tcp_recv_timeout.to_i, 0)
  case error
  when nil
    buf
  else
    ""
  end
end
socket_read(socket, size, timeout_seconds, total_attempts) click to toggle source
# File lib/da_funk/transaction/download.rb, line 164
def socket_read(socket, size, timeout_seconds, total_attempts)
  total_buffer = ""
  error = nil
  attempts = 0
  timeout = Time.now + timeout_seconds
  loop do
    buf = socket.recv_nonblock(size - total_buffer.size)
    total_buffer << buf.to_s
    break if total_buffer.size >= size
    break(error = :socket_closed) if buf.nil?
    if (Time.now > timeout)
      attempts+=1
      timeout = Time.now + timeout_seconds
      break(error = :attempts_exceeded) if attempts > total_attempts
    end
    break(error = :user_cancel) if (getc(200) == Device::IO::CANCEL)
  end
  [total_buffer, error]
end
tmp_file(path) click to toggle source
# File lib/da_funk/transaction/download.rb, line 317
def tmp_file(path)
  paths = path.split("/")
  paths[-1] = "tmp_#{paths.last}"
  paths.join("/")
end