Class: Pantry::Communication::FileService

Inherits:
Object
  • Object
show all
Includes:
Celluloid::ZMQ
Defined in:
lib/pantry/communication/file_service.rb,
lib/pantry/communication/file_service/file_progress.rb

Overview

FileService manages the sending and receiving of files that are too big to cleanly send as a plain ZeroMQ message. Every Client and Server has its own FileService handler which can manage both sending and receiving files from each other.

Setting up a file transfer processes backwards from what may be expected. As the Receiver actually requests chunks from the Sender, a protocol that’s heavily influenced by zguide.zeromq.org/page:all#Transferring-Files, a Receiver must be initiated first on the receiving end, which will then pass back the appropriate information (receiver_uuid and file upload UUID) a Sender needs to start up and run.

From this the two parts complete the process automatically. A Receiver writes the data it receives in a tempfile, and must be configured with a completion block to move the uploaded file to its final location.

To ensure this object has as little special-casing code as possible, the communication takes place in a ZeroMQ ROUTER <-> ROUTER topology.

Defined Under Namespace

Classes: ReceiveFile, ReceivingFile, SendFile, SendingFile, UploadInfo

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(server_host, port, security) ⇒ FileService

Returns a new instance of FileService.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/pantry/communication/file_service.rb', line 28

def initialize(server_host, port, security)
  @host = server_host
  @port = port

  @socket = Celluloid::ZMQ::RouterSocket.new
  @socket.set(::ZMQ::ROUTER_MANDATORY, 1)
  @socket.identity = @identity = SecureRandom.uuid
  Communication.configure_socket(@socket)

  @security = security
  @security.configure_socket(@socket)

  @receiver = FileService::ReceiveFile.new_link(self)
  @sender   = FileService::SendFile.new_link(self)
end

Instance Attribute Details

#identityObject (readonly)

Returns the value of attribute identity.



26
27
28
# File 'lib/pantry/communication/file_service.rb', line 26

def identity
  @identity
end

Instance Method Details

#receive_file(size, checksum) ⇒ Object

Inform the service that it will soon be receiving a file of the given size and checksum. Returns a UploadInfo struct with the information for the Sender.



70
71
72
73
74
75
# File 'lib/pantry/communication/file_service.rb', line 70

def receive_file(size, checksum)
  Pantry.logger.debug("[FileService] Receiving file of size #{size} and checksum #{checksum}")
  @receiver.receive_file(size, checksum).tap do |info|
    info.receiver_uuid = @socket.identity
  end
end

#receive_message(from_identity, message) ⇒ Object



93
94
95
96
# File 'lib/pantry/communication/file_service.rb', line 93

def receive_message(from_identity, message)
  @sender.async.receive_message(from_identity, message)
  @receiver.async.receive_message(from_identity, message)
end

#runObject



62
63
64
65
# File 'lib/pantry/communication/file_service.rb', line 62

def run
  @running = true
  self.async.process_messages
end

#secure_with(security_handler) ⇒ Object



44
45
46
# File 'lib/pantry/communication/file_service.rb', line 44

def secure_with(security_handler)
  @security = security_handler
end

#send_file(file_path, receiver_uuid, file_uuid) ⇒ Object

Inform the service that we want to start sending a file up to the receiver who’s listening on the given UUID.



79
80
81
82
# File 'lib/pantry/communication/file_service.rb', line 79

def send_file(file_path, receiver_uuid, file_uuid)
  Pantry.logger.debug("[FileService] Sending file #{file_path} to #{receiver_uuid}")
  @sender.send_file(file_path, receiver_uuid, file_uuid)
end

#send_message(identity, message) ⇒ Object



84
85
86
87
88
89
90
91
# File 'lib/pantry/communication/file_service.rb', line 84

def send_message(identity, message)
  @socket.write(
    [
      identity,
      SerializeMessage.to_zeromq(message)
    ].flatten
  )
end

#shutdownObject



58
59
60
# File 'lib/pantry/communication/file_service.rb', line 58

def shutdown
  @running = false
end

#start_clientObject



53
54
55
56
# File 'lib/pantry/communication/file_service.rb', line 53

def start_client
  @socket.connect("tcp://#{@host}:#{@port}")
  run
end

#start_serverObject



48
49
50
51
# File 'lib/pantry/communication/file_service.rb', line 48

def start_server
  @socket.bind("tcp://#{@host}:#{@port}")
  run
end