Skip to content

Instantly share code, notes, and snippets.

@tompng
Last active December 14, 2024 05:29
Show Gist options
  • Save tompng/d3d231403c87687ce60f24f894c7ecff to your computer and use it in GitHub Desktop.
Save tompng/d3d231403c87687ce60f24f894c7ecff to your computer and use it in GitHub Desktop.
simple directory uploader
require 'socket'
require 'json'
endpoint = ARGV[0]
src = ARGV[1]
dst = ARGV[2] || ''
unless endpoint =~ /\A.+:\d+\z/ && src
puts "ARGV[0]: host:port"
puts "ARGV[1]: src dir"
puts "ARGV[2]: dst dir"
exit
end
dst.gsub(/\A\/+|\/+\z/, '')
files = Dir.glob("#{src}/**/*")
host, port = endpoint.split(':')
socket = TCPSocket.new(host, port.to_i)
socket.puts JSON.dump({ type: 'stat', dir: dst })
server_files = JSON.parse socket.gets
server_file_sizes = server_files.map { |f| [f['path'], f['size']] }.to_h
files.each do |path|
next unless File.file?(path)
actual_size = File.size(path)
server_size = server_file_sizes[path[src.size + 1..path.size]]
if actual_size != server_size
socket.puts JSON.dump({ type: 'upload', path: "#{dst}/#{path[src.size + 1..path.size]}", size: actual_size })
socket.write File.read(path)
puts "upload: #{path} (#{actual_size})"
raise unless socket.gets.chomp == '"ok"'
end
end
socket.close
require 'socket'
require 'json'
require 'fileutils'
port = ARGV[0]
unless /\A\d+\z/.match?(port)
puts "ARGV[0]: port number"
exit 1
end
FILE_DIR = File.absolute_path('files', __dir__)
Dir.mkdir(FILE_DIR) unless Dir.exist?(FILE_DIR)
def handle(socket)
puts 'start'
while (raw_req = socket.gets)
req = JSON.parse raw_req.force_encoding('UTF-8')
case req['type']
when 'stat'
dir = File.absolute_path(req['dir'], FILE_DIR)
raise "invalid dir: #{dir}" unless dir.start_with?(FILE_DIR + '/') || dir == FILE_DIR
files = []
Dir.glob("#{dir}/**/*").each do |path|
files << { path: path[dir.size + 1..], size: File.size(path) }
end
socket.puts JSON.dump(files)
when 'upload'
path = File.absolute_path(req['path'], FILE_DIR)
raise "invalid path: #{path}" unless path.start_with?(FILE_DIR + '/')
FileUtils.mkdir_p(File.dirname(path))
bytesize = req['size']
data = +''.b
while data.bytesize < bytesize
data << socket.readpartial([bytesize - data.bytesize, 65536].min)
end
File.write path, data
puts "write: #{path} (#{bytesize})"
socket.puts(JSON.dump('ok'))
end
end
rescue => e
puts e
puts e.backtrace
ensure
puts 'close'
socket.close
end
server = TCPServer.new(port.to_i)
p server.addr
loop do
socket = server.accept
Thread.new do
handle(socket)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment