-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.rb
More file actions
148 lines (125 loc) · 4.44 KB
/
server.rb
File metadata and controls
148 lines (125 loc) · 4.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# frozen_string_literal: true
require 'socket'
require 'json'
require 'pg'
server = TCPServer.new(3000)
puts 'Server started'
$stdout.flush
class InvalidDataError < StandardError; end
class NotFoundError < StandardError; end
def parse_request(client)
line = client.gets
verb, path, version = line.split(' ')
puts "Verb: #{verb}, Path: #{path}, Version: #{version}"
id = path.split('/')[2].to_i
puts id
action = path.split('/')[3]
request = "#{verb} /clientes/:id/#{action}"
params = { 'id' => id }
headers = {}
while (line = client.gets)
break if line == "\r\n"
key, value = line.split(': ')
headers[key] = value.strip
end
if headers['Content-Length']
body = client.read(headers['Content-Length'].to_i)
params.merge!(JSON.parse(body))
end
[request, params]
end
conn = PG.connect(host: ENV['DB_HOST'] || 'localhost',
user: 'postgres',
password: 'postgres',
dbname: 'postgres',
port: 5432)
loop do
client = server.accept
request, params = parse_request(client)
raise NotFoundError if params.empty?
puts "Request: #{request}, Params: #{params}"
id = params['id']
raise NotFoundError if id.nil?
raise NotFoundError unless id.is_a?(Integer) && id.positive?
case request
in 'GET /clientes/:id/extrato'
sql_account = "SELECT * FROM accounts WHERE id = #{id} LIMIT 1 FOR UPDATE"
sql_transactions = <<~SQL
SELECT amount, transaction_type, description, TO_CHAR(date, 'YYYY-MM-DD HH:MI:SS.US') AS date
FROM transactions
WHERE transactions.account_id = #{id}
ORDER BY date DESC
LIMIT 10
SQL
conn.transaction do |c|
account = c.exec(sql_account).first
raise NotFoundError unless account
transactions = c.exec(sql_transactions)
body = {
"saldo": {
"total": account['balance'].to_i,
"data_extrato": Time.now.strftime('%Y-%m-%d'),
"limite": account['limit_amount'].to_i
},
"ultimas_transacoes": transactions.map do |transaction|
{
"valor": transaction['amount'].to_i,
"tipo": transaction['transaction_type'],
"descricao": transaction['description'],
"realizada_em": transaction['date']
}
end
}
puts 'Success!'
client.puts "HTTP/1.1 200\r\nContent-Type: application/json\r\n\r\n#{body.to_json}"
client.close
end
in 'POST /clientes/:id/transacoes'
raise InvalidDataError if params.empty? || params.nil?
valor = params['valor']
tipo = params['tipo']
descricao = params['descricao']
raise InvalidDataError if id.nil? || valor.nil? || tipo.nil? || descricao.nil?
raise InvalidDataError if valor && (!valor.is_a?(Integer) || !valor.positive?)
raise InvalidDataError if descricao&.empty?
raise InvalidDataError if descricao && descricao.size > 10
raise InvalidDataError unless %w[d c].include?(params['tipo'])
puts "Id: #{id}, Valor: #{valor}, Tipo: #{tipo}, Descricao: #{descricao}"
conn.transaction do |c|
sql_account = "SELECT * FROM accounts WHERE id = #{id} LIMIT 1 FOR UPDATE"
account = conn.exec(sql_account).first
raise NotFoundError if account.nil?
operator = '+'
puts "Account: {id: #{account['id']}}"
if tipo == 'd'
operator = '-'
raise InvalidDataError if (account['limit_amount'].to_i + account['balance'].to_i) <= valor
end
sql_insert_transaction = "INSERT INTO transactions (account_id, amount, transaction_type, description, date) VALUES (#{id}, #{valor}, '#{tipo}', '#{descricao}', NOW())"
sql_update_balance = "UPDATE accounts SET balance = balance #{operator} #{valor} WHERE id = #{id} RETURNING *"
c.exec(sql_insert_transaction)
account = c.exec(sql_update_balance).first
body = {
"saldo": account['balance'].to_i,
"limite": account['limit_amount'].to_i
}
puts 'Success!'
client.puts "HTTP/1.1 200\r\nContent-Type: application/json\r\n\r\n#{body.to_json}"
client.close
end
else
raise NotFoundError
end
rescue NotFoundError
puts 'Not found'
status = 404
body = {}
client.puts "HTTP/1.1 #{status}\r\nContent-Type: application/json\r\n\r\n#{body.to_json}"
client.close
rescue InvalidDataError
puts 'Invalid data'
status = 422
body = {}
client.puts "HTTP/1.1 #{status}\r\nContent-Type: application/json\r\n\r\n#{body.to_json}"
client.close
end