simple-transfer 0.0.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f69f3c96aad7319e99191e7e4cc291a9b75a8997aeec61c8acd6fac55e230322
4
- data.tar.gz: 9ab1d2e0b548b65e6f09d677f0295ab16b87d5dab71be58c7d2faa516c1ec92c
3
+ metadata.gz: 83a010fdd44ee8da6b309e8b61d757d79e17979e6e6cd25fe28e639f9f57e483
4
+ data.tar.gz: d6b07967f13aad9e4ef32616d3308d99f624df9c1be1050a9fbcaed29f981f7d
5
5
  SHA512:
6
- metadata.gz: 62867c898cad672b01ee0f35d976d770246a7e44725cf37fdab3db79d6a0a97d476363a3b300c7dfccb3969ba67f7ad8b62181eaf9d010eae8f978770c1d5989
7
- data.tar.gz: 5b7b9a30ff2d42f10b8507157892f0677fadf20d1143ef27a9a3668dda004492821e092aba78f433faa19a6b8a18c30b83d62cbffb5906fd7841260a1a9755cb
6
+ metadata.gz: 7b13491d37fbc3ff29ad6eed31ff4f7c275ce85cfd837ac463e951fe530f065b1952a359e68329b0e07569416aee72592bc7332000adf15a6a7665df9bb42f1f
7
+ data.tar.gz: 023dbde679d7dbd4883391fff0641db0be52ab8eb53b84bea18744691751cf55ef66ce5580885b7891147d451358457e5de455d5e51ab530bf9c0c38d174886c
@@ -0,0 +1,83 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require_relative "../lib/transfer.rb"
4
+ require_relative "../lib/repl.rb"
5
+
6
+ include SimpleTransfer
7
+
8
+ $valid_server_commands = ["--server", "-s", "server", "--serve"]
9
+ $valid_client_commands = ["--client", "-c", "client", "--cli"]
10
+
11
+ def numeric?(str)
12
+ true if Float(str) rescue false
13
+ end
14
+
15
+ def is_valid_command(command)
16
+ if $valid_server_commands.include?(command)
17
+ return "server"
18
+ elsif $valid_client_commands.include?(command)
19
+ return "client"
20
+ end
21
+ return nil
22
+ end
23
+
24
+ def init_server(port)
25
+ myserver = Server.new(port)
26
+ myserver.start()
27
+ end
28
+
29
+ def init_client(server_addr, server_port)
30
+ myshell = STShell.new(server_addr, server_port)
31
+ myshell.init_loop()
32
+ end
33
+
34
+
35
+ def check_mode(mode)
36
+ if mode.nil?
37
+ puts "Please provide a mode, friend; >:3\
38
+ --server <port> or --client <server_addr> <server_port>"
39
+ return false
40
+ elsif not is_valid_command(mode)
41
+ puts "#{mode} is not a valid mode, friend; >:3\
42
+ --server <port> or --client <server_addr> <server_port>"
43
+ return false
44
+ end
45
+ return true
46
+ end
47
+
48
+ def check_port(port)
49
+ if port.nil?
50
+ puts "Please provide a port number, friend :3"
51
+ return false
52
+ elsif not numeric?(port)
53
+ puts "Port number must be an integer, friend :3"
54
+ return false
55
+ end
56
+ return true
57
+ end
58
+
59
+ def check_addr(mode, addr)
60
+ if addr.nil? and is_valid_command(mode) == "client"
61
+ puts "Please provide a server address, friend :3"
62
+ return false
63
+ end
64
+ return true
65
+ end
66
+
67
+ def main()
68
+ mode, port, addr = ARGV
69
+ if not check_mode(mode) or not check_port(port)
70
+ return
71
+ end
72
+ if not check_addr(mode, addr)
73
+ return
74
+ end
75
+ if is_valid_command(mode) == "server"
76
+ init_server(port)
77
+ else
78
+ init_client(addr, port)
79
+ end
80
+ puts "Goodbye friend, hope you enjoyed Simple-Transfer :3" #!
81
+ end
82
+
83
+ main() # real!
data/lib/repl.rb ADDED
@@ -0,0 +1,106 @@
1
+
2
+ require_relative "transfer.rb"
3
+
4
+
5
+ $logo = <<EOF
6
+
7
+ .---. . .
8
+ \___ . ,-,-. ,-. | ,-. |- ,-. ,-. ,-. ,-. ," ,-. ,-.
9
+ \ | | | | | | | |-' -- | | ,-| | | `-. |- |-' |
10
+ `---' ' ' ' ' |-' `' `-' `' ' `-^ ' ' `-' | `-' '
11
+ | '
12
+ '
13
+ EOF
14
+
15
+
16
+ class STShell
17
+ def initialize(server_addr, port)
18
+ @port = port
19
+ @client = SimpleTransfer::Sender.new(server_addr, port, logging=true)
20
+ end
21
+
22
+ def self.list_files(path)
23
+ Dir.entries(path).each do |f|
24
+ if File.directory?(f)
25
+ puts "#{f}/"
26
+ else
27
+ puts f
28
+ end
29
+ end
30
+ end
31
+
32
+
33
+ def eval(query)
34
+ p1, p2 = query.split(" ")
35
+ if p1 == "clear"
36
+ system "clear"
37
+ elsif p1 == "send_file"
38
+ if File.directory?(p2)
39
+ puts "You can't send a directory as a file, friend!"
40
+ else
41
+ @client.send_file(p2)
42
+ end
43
+ elsif p1 == "send_directory"
44
+ if not File.directory?(p2)
45
+ puts "You can't send a file as a directory, friend!"
46
+ else
47
+ @client.send_directory(p2)
48
+ end
49
+ elsif p1 == "cd"
50
+ Dir.chdir(p2)
51
+ elsif p1 == "ls"
52
+ if p2.nil?
53
+ STShell.list_files(Dir.pwd)
54
+ else
55
+ STShell.list_files(p2)
56
+ end
57
+ elsif p1 == "help"
58
+ help()
59
+ else
60
+ p "I don't recognize this command: `#{p1}` friend!"
61
+ end
62
+ end
63
+
64
+ def help()
65
+ puts "Type 'send_file <filename>' to send a file"
66
+ puts "Type 'send_directory <directory>' to send a directory"
67
+ puts "Type 'cd <directory>' to change directory"
68
+ puts "Type 'ls <directory>' to list directory contents"
69
+ puts "Type help to see this message"
70
+ end
71
+
72
+ def read()
73
+ query = $stdin.gets.chomp
74
+ #puts query, echo is very annoying
75
+ return query
76
+ end
77
+
78
+ def print()
79
+ Kernel.print("[ST]🍀 #{Dir.pwd} >>>> ")
80
+ end
81
+
82
+ def init_loop()
83
+ puts $logo
84
+ puts "STShell initialized on port #{@port}!"
85
+ puts "Hello friend, thank you for using simple transfer!"
86
+ puts "Are you ready to drown in simplicity?"
87
+ puts "It is indeed extremely simple:"
88
+ help()
89
+ repl()
90
+ #real...
91
+ # let it be
92
+ end
93
+
94
+ def repl()
95
+ while true
96
+ print()
97
+ query = read()
98
+ begin
99
+ eval(query)
100
+ rescue => e
101
+ p e
102
+ puts "An error occurred, friend! >:3"
103
+ end
104
+ end
105
+ end
106
+ end
data/lib/transfer.rb CHANGED
@@ -1,225 +1,196 @@
1
-
2
- require_relative 'buffer/buffer'
3
- require 'socket'
4
- require 'fileutils'
5
-
6
-
7
-
8
- $socket = Socket::new(Socket::AF_INET, Socket::SOCK_STREAM)
9
- $socket.setsockopt(:SOCKET, :REUSEADDR, true)
10
-
11
- $PORT = 30317
12
-
13
-
14
- $MAX_BUFFER_SIZE = 65000
15
-
16
-
17
- def set_server(port=$PORT)
18
- myaddr = Socket.pack_sockaddr_in(port, '0.0.0.0')
19
-
20
- $socket.bind(myaddr)
21
-
22
- $socket.listen(5)
23
-
24
- puts "server listening on port: #{port}."
25
- end
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
- def accept_client
37
- puts "waiting for the client to connect..."
38
-
39
- $conn = $socket.accept
40
-
41
- puts "#{$conn[1].ip_unpack()[0]} has connected!"
42
- end
43
-
44
-
45
-
46
-
47
-
48
- def connectto_target(ip, port=$PORT)
49
- remote_addr = Socket.pack_sockaddr_in(port, ip)
50
-
51
- puts "trying to connect to the target..."
52
- $socket.connect(remote_addr)
53
- puts "connected to the target!"
54
- end
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
- def recv_file
66
-
67
- file_size = $conn[0].recv(1024).chomp
68
-
69
- unless file_size == ''
70
-
71
- begin
72
- file_size = Integer(file_size)
73
- rescue ArgumentError
74
- puts "Oops, there was a problem..."
75
-
76
- return nil
77
- end
78
-
79
- else
80
- puts "file receiving ended."
81
- exit()
82
- end
83
-
84
- filename = $conn[0].recv(1024).chomp
85
-
86
- if file_size > 31457280
87
- puts "#{filename} is bigger than 30 MB, cannot save!"
88
-
89
- return nil
90
-
91
-
92
- elsif file_size < $MAX_BUFFER_SIZE
93
- file_content = $conn[0].recv($MAX_BUFFER_SIZE).chomp
94
-
95
- else
96
- file_content = ''
97
-
98
- while true
99
- data = $conn[0].recv($MAX_BUFFER_SIZE).chomp
100
-
101
- if data == "END"
102
- break
103
- else
104
- file_content += data
105
- end
106
-
107
- end
108
- end
109
-
110
-
111
- begin
112
- open("./"+filename, "a").write(file_content)
113
-
114
- rescue Errno::ENOENT
115
- dirname = File.dirname(filename)
116
-
117
- unless File.directory?(dirname)
118
- FileUtils.mkdir_p(dirname)
119
- open("./"+filename, "a").write(file_content)
120
- end
121
- end
122
-
123
- puts "received file '#{filename}'"
124
- end
125
-
126
-
127
-
128
-
129
-
130
- def send_file(filename)
131
-
132
- puts "sending #{filename}..."
133
-
134
- file_content = open(filename, "r").read()
135
-
136
- file_size = file_content.length
137
-
138
- $socket.puts(file_size)
139
- sleep(0.5)
140
-
141
- $socket.puts(filename)
142
- sleep(0.5)
143
-
144
- if file_size > 31457280
145
- return nil
146
-
147
- elsif file_size < $MAX_BUFFER_SIZE
148
- $socket.puts(file_content)
149
-
150
- else
151
- buffers = buffer(file_content, buffer_size=$MAX_BUFFER_SIZE)
152
-
153
- for buffer in buffers.values
154
- $socket.puts(buffer)
155
- sleep(0.1)
156
-
157
- end
158
-
159
- $socket.puts "END"
160
- end
161
- end
162
-
163
-
164
-
165
-
166
-
167
- def send_dir(dirname)
168
- Dir["#{dirname}/**/*"].each do |file|
169
- unless File.directory?(file)
170
- send_file(file)
171
- end
172
- end
1
+ require "socket"
2
+ require "fileutils"
3
+ require "time"
4
+
5
+ module SimpleTransfer
6
+ def log_transfer(message, level = "INFO")
7
+ Kernel.puts "[#{level}] [%s] #{message}" % Time.now.utc.iso8601
8
+ end
9
+
10
+ def progress_bar(download, length)
11
+ i = (download.to_f / length.to_f * 30).to_i
12
+ return "[" + "❚" * i + " " * (30 - i) + "]"
13
+ end
14
+
15
+ def log_progress(downloaded, length, filename)
16
+ Kernel.print "\r[TRANSFER!] Downloading #{filename}... #{downloaded}/#{length} bytes"
17
+ end
18
+
19
+ class Server < TCPServer
20
+ @@recv_size = 1024 * 30
21
+
22
+ def initialize(*args)
23
+ super(*args)
24
+ @logging = true
25
+ end
26
+
27
+ def port()
28
+ return self.addr[1]
29
+ end
30
+
31
+ def recv_chunk()
32
+ return @conn.recv(@@recv_size)
33
+ end
34
+
35
+ def init_transfer()
36
+ @conn.send("SYNC OK", 1024)
37
+ data_length = Integer(recv_chunk()) # receive data length
38
+ log_transfer("received data length: #{data_length}", level = "DEBUGGING") if @logging
39
+ @conn.send("LENGTH OK", 1024)
40
+ filename = recv_chunk() # receive file name
41
+ log_transfer("received filename: #{filename}", level = "DEBUGGING") if @logging
42
+ @conn.send("FILENAME OK", 1024)
43
+ log_transfer(
44
+ "transfer initiated for #{filename} size: #{data_length}", level = "INFO"
45
+ ) if @logging
46
+ return data_length, filename
47
+ end
48
+
49
+ def recv_initiation()
50
+ start_sign = recv_chunk() # wait for the client to sync
51
+ log_transfer("received start sign: #{start_sign}", level = "DEBUGGING") if @logging
52
+ if start_sign != "SYNC NOW"
53
+ if start_sign.empty?
54
+ return 0
55
+ end
56
+ return nil
57
+ end
58
+ return init_transfer()
59
+ end
60
+
61
+ def handle_init()
62
+ init_data = recv_initiation()
63
+ if init_data == nil
64
+ log_transfer("Failed to receive initiation data", level = "WARNING") if @logging
65
+ return false, nil
66
+ elsif init_data == 0
67
+ log_transfer("Connection closed by the client", level = "WARNING") if @logging
68
+ return false, 0
69
+ return false, init_data
70
+ end
71
+ return init_data
72
+ end
73
+
74
+ def recv_file()
75
+ init = handle_init()
76
+ if not init[0]
77
+ return init[1]
78
+ end
79
+ data_length, filename = init
80
+ data = ""
81
+ while data.length < data_length
82
+ data += recv_chunk()
83
+ sleep(0.01)
84
+ log_progress(data.length, data_length, filename) if @logging
85
+ end
86
+ Kernel.print "\n"
87
+ if data.length != data_length
88
+ log_transfer(
89
+ "partial data received for #{filename}", level = "WARNING"
90
+ ) if @logging
91
+ end
92
+ return data, filename
93
+ end
94
+
95
+ def copyto_local(data)
96
+ fdata, filename = data
97
+ dirname = File.dirname(filename)
98
+ if not File.exist?('.' + dirname)
99
+ FileUtils.mkdir_p(dirname)
100
+ end
101
+ File.open(filename, "wb") do |f|
102
+ f.write(fdata)
103
+ end
104
+ end
105
+
106
+ def start()
107
+ log_transfer("(Re)starting Simple-Transfer server!") if @logging
108
+ log_transfer("listening at port %s..." % port) if @logging
109
+ self.listen(16)
110
+ @conn = accept()
111
+ log_transfer("Accepted client: #{@conn.peeraddr[2]}: #{@conn.peeraddr[1]}")
112
+ while true
113
+ filedata = recv_file()
114
+ if filedata == nil
115
+ next
116
+ elsif filedata == 0
117
+ start()
118
+ return
119
+ end
120
+ copyto_local(filedata)
121
+ sleep 0.01
122
+ end
123
+ end
124
+ end
125
+
126
+ class Sender < TCPSocket
127
+ @@chunk_size = 5000
128
+
129
+ def initialize(host, port, logging = false)
130
+ super(host, port)
131
+ @logging = logging
132
+ end
133
+
134
+ def self.buffer(data)
135
+ buffers = Array.new
136
+ data = String(data)
137
+ buffer_amount = @@chunk_size > data.length ? 1 : data.length / @@chunk_size + 1
138
+
139
+ for i in 0..buffer_amount - 1
140
+ buffers.push data.slice(i * @@chunk_size, @@chunk_size)
141
+ end
142
+
143
+ return buffers
144
+ end
145
+
146
+ def self.pack(filename, data)
147
+ buffers = self.buffer(data)
148
+
149
+ buffers.unshift filename
150
+ buffers.unshift String(data.length)
151
+ return buffers
152
+ end
153
+
154
+ def send_chunk(chunk)
155
+ send(chunk, @@chunk_size)
156
+ end
157
+
158
+ def initiate_exchange(package)
159
+ send_chunk("SYNC NOW")
160
+ log_transfer("sent start sign: SYNC NOW", level = "DEBUGGING") if @logging
161
+ recv(1024)
162
+ send_chunk(package.shift)
163
+ log_transfer("sent data length", level = "DEBUGGING") if @logging
164
+ recv(1024)
165
+ send_chunk(package.shift)
166
+ log_transfer("sent filename", level = "DEBUGGING") if @logging
167
+ recv(1024)
168
+ end
169
+
170
+ def send_file(filename)
171
+ package = nil
172
+ File.open(filename, "rb") do |f|
173
+ log_transfer("sending #{f.path}") if @logging
174
+ package = Sender.pack(filename, f.read())
175
+ end
176
+ initiate_exchange(package)
177
+ package.each do |chunk|
178
+ send_chunk(chunk)
179
+ end
180
+ end
181
+
182
+ def scan_directory(directory_name)
183
+ return Dir["%s/**/*" % directory_name]
184
+ end
185
+
186
+ def send_directory(directory)
187
+ scan_directory(directory).each do |f|
188
+ #sleep because there is no sync for end of transfer
189
+ sleep 0.5
190
+ if File.directory?(f)
191
+ send_directory(f)
192
+ else send_file(f) end
193
+ end
194
+ end
195
+ end
173
196
  end
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
- module Transfer
195
- def self.run_server
196
- set_server
197
- accept_client
198
- while true
199
- begin
200
- recv_file
201
- ensure
202
- end
203
- end
204
- end
205
-
206
- def self.transfer(ip, file)
207
- begin
208
- connectto_target(ip)
209
- rescue Errno::EISCONN
210
- end
211
-
212
- if File.directory?(file)
213
- send_dir(file)
214
- else
215
- send_file(file)
216
- end
217
- end
218
- end
219
-
220
-
221
-
222
-
223
-
224
-
225
-
metadata CHANGED
@@ -1,29 +1,33 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple-transfer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Burzum
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-16 00:00:00.000000000 Z
11
+ date: 2025-02-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description:
14
- email:
15
- executables: []
13
+ description: |-
14
+ An extremely simple gem that relies on the TCP stack for transfer of files over a IP network.
15
+ It is as simple as it gets. Relies on no other protocol.
16
+ email:
17
+ - atifaydinturanli@gmail.com
18
+ executables:
19
+ - simple-transfer
16
20
  extensions: []
17
- extra_rdoc_files:
18
- - README.md
21
+ extra_rdoc_files: []
19
22
  files:
20
- - README.md
21
- - lib/buffer/buffer.rb
23
+ - bin/simple-transfer
24
+ - lib/repl.rb
22
25
  - lib/transfer.rb
23
- homepage:
24
- licenses: []
26
+ homepage: https://github.com/unhappygirl/simple-transfer
27
+ licenses:
28
+ - MIT
25
29
  metadata: {}
26
- post_install_message:
30
+ post_install_message:
27
31
  rdoc_options: []
28
32
  require_paths:
29
33
  - lib
@@ -38,8 +42,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
38
42
  - !ruby/object:Gem::Version
39
43
  version: '0'
40
44
  requirements: []
41
- rubygems_version: 3.1.2
42
- signing_key:
45
+ rubygems_version: 3.4.20
46
+ signing_key:
43
47
  specification_version: 4
44
- summary: A gem for transfering files up to 30 mbs simply and with ease.
48
+ summary: A gem for transfering files over your network with extreme simplicity -and
49
+ fast.
45
50
  test_files: []
data/README.md DELETED
@@ -1,56 +0,0 @@
1
- This gem is created to make transfering whole directories; scripts, photos, videos, any files that are up to 30 MB simple and easy.
2
-
3
- **Please don't forget to read the notes section.**
4
-
5
-
6
-
7
- ## Usage
8
-
9
- As the name suggests, to transfer files is simple and easy with ```simple-transfer```.
10
-
11
- The ```Transfer``` module has two methods: ```Transfer::run_server``` and ```Transfer::transfer```.
12
-
13
- #### ```Transfer::run_server```
14
-
15
- This method will run a server on your local machine. Once you call it, the server will listen for connections.
16
-
17
- The server is for receiving files only. So the machine that will receive files needs to call this method first.
18
-
19
- #### ```Transfer::transfer```
20
- This method takes two arguments, first argument is the IPv4 of the target; second one is the name of the file, directory that will be sent.
21
-
22
- It will try to connect to the target machine if not already connected and send the files that are specified.
23
-
24
-
25
- ## Example
26
-
27
-
28
- The server:
29
-
30
- ```
31
- require 'transfer'
32
- include Transfer
33
-
34
- Transfer.run_server
35
-
36
- ```
37
-
38
- The client:
39
-
40
- ```
41
- require 'transfer'
42
- include Transfer
43
-
44
- Transfer.transfer('192.168.1.25', 'foo.png')
45
-
46
- ```
47
-
48
- ## Notes
49
-
50
- * Using ```simple-transfer``` from the interactive ruby shell is terribly bad.
51
-
52
- * ```simple-transfer``` uses tcp sockets and buffers data that are bigger than 65 KB. If you are receiving files only partially and encountering strange errors, try setting the ```$MAX_BUFFER_SIZE``` constant to a lower value.
53
-
54
- * To make ```simple-transfer``` work on the internetwork, port forwarding is required.
55
-
56
- * Relative paths are NOT supported in simple-transfer. Files need to be in the cwd to be transfered.
data/lib/buffer/buffer.rb DELETED
@@ -1,27 +0,0 @@
1
-
2
-
3
-
4
- def buffer(data, buffer_size=65000)
5
-
6
- labelnum = 0
7
-
8
- buffers = Hash.new
9
-
10
- data = String(data)
11
-
12
- buffer_amount = ( data.length / buffer_size ) + 1
13
-
14
- sindex = 0
15
-
16
- while labelnum != buffer_amount
17
- buffers["buffer#{labelnum}"] = data.slice(sindex, buffer_size)
18
-
19
- sindex += buffer_size
20
-
21
- labelnum += 1
22
-
23
- end
24
-
25
- return buffers
26
-
27
- end