Total Complexity | 58 |
Total Lines | 330 |
Duplicated Lines | 0 % |
Complex classes like Controller often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | require 'midb/server_model' |
||
16 | # This controller controls the behavior of the midb server. |
||
17 | class Controller |
||
18 | # Attribute declaration here |
||
19 | # |
||
20 | # @!attribute args |
||
21 | # @return [Array<String>] Arguments passed to the binary. |
||
22 | # @!attribute config |
||
23 | # @return [Hash] Contains the project's configuration, saved in .midb.yaml |
||
24 | # @!attribute db |
||
25 | # @return [String] Database name (if SQLite is the engine, file name without extension) |
||
26 | # @!attribute http_status |
||
27 | # @return [String] HTTP status code and string representation for the header |
||
28 | # @!attribute port |
||
29 | # @return [Fixnum] Port where the server will listen. |
||
30 | # @!attribute h |
||
31 | # @return [Object] MIDB::API::Hooks instance |
||
32 | attr_accessor :args, :config, :db, :http_status, :port, :hooks |
||
33 | |||
34 | # Convert an on/off string to a boolean |
||
35 | # |
||
36 | # @param text [String] Text to convert to bool |
||
37 | def to_bool(text) |
||
38 | if text == "on" || text == "true" || text == "yes" |
||
39 | return true |
||
40 | elsif text == "off" || text == "false" || text == "no" |
||
41 | return false |
||
42 | else |
||
43 | return nil |
||
44 | end |
||
45 | end |
||
46 | |||
47 | # Constructor for this controller. |
||
48 | # |
||
49 | # @param args [Array<String>] Arguments passed to the binary. |
||
50 | def initialize(args, hooks=nil) |
||
51 | # Default values |
||
52 | # |
||
53 | # @see #http_status |
||
54 | # @see #args |
||
55 | # @see #config |
||
56 | # @see #port |
||
57 | @http_status = "200 OK" |
||
58 | @args = args |
||
59 | @config = Hash.new() |
||
60 | @port = 8081 |
||
61 | if hooks == nil |
||
62 | # At some point someone should register this. |
||
63 | @hooks = MIDB::API::Hooks.new |
||
64 | else |
||
65 | @hooks = hooks |
||
66 | end |
||
67 | end |
||
68 | |||
69 | ##################### |
||
70 | # Server commands # |
||
71 | ##################### |
||
72 | |||
73 | # $ midb help |
||
74 | # |
||
75 | # Show some help for either midb or a command. |
||
76 | def do_help() |
||
77 | if @args.length > 1 |
||
78 | case @args[1] |
||
79 | when "bootstrap" |
||
80 | MIDB::Interface::Server.help(:bootstrap) |
||
81 | when "set" |
||
82 | MIDB::Interface::Server.help(:set) |
||
83 | when "start" |
||
84 | MIDB::Interface::Server.help(:start) |
||
85 | when "serve" |
||
86 | MIDB::Interface::Server.help(:serve) |
||
87 | when "unserve" |
||
88 | MIDB::Interface::Server.help(:unserve) |
||
89 | else |
||
90 | MIDB::Interface::Errors.die(:no_help) |
||
91 | end |
||
92 | else |
||
93 | MIDB::Interface::Server.help(:list) |
||
94 | end |
||
95 | end |
||
96 | |||
97 | # $ midb bootstrap |
||
98 | # |
||
99 | # Bootstrap a new midb project in the active directory. |
||
100 | def do_bootstrap() |
||
101 | if File.file?(".midb.yaml") |
||
102 | MIDB::Interface::Errors.die(:already_project) |
||
103 | else |
||
104 | # If the file doesn't exist it, create it with the default stuff |
||
105 | @config["serves"] = [] |
||
106 | @config["status"] = :asleep # The server is initially asleep |
||
107 | @config["apikey"] = "midb-api" # This should be changed, it's the private API key |
||
108 | # Optional API key for GET methods (void by default) |
||
109 | @config["apigetkey"] = nil |
||
110 | @config["dbengine"] = :sqlite3 # SQLite is the default engine |
||
111 | # Default DB configuration for MySQL and other engines |
||
112 | @config["dbhost"] = "localhost" |
||
113 | @config["dbport"] = 3306 |
||
114 | @config["dbuser"] = "nobody" |
||
115 | @config["dbpassword"] = "openaccess" |
||
116 | # New settings - privacy |
||
117 | @config["privacyget"] = false |
||
118 | @config["privacypost"] = true |
||
119 | @config["privacyput"] = true |
||
120 | @config["privacydelete"] = true |
||
121 | |||
122 | File.open(".midb.yaml", 'w') do |l| |
||
123 | l.write @config.to_yaml |
||
124 | end |
||
125 | # Create json/ and db/ directory if it doesn't exist |
||
126 | Dir.mkdir("json") unless File.exists?("json") |
||
127 | Dir.mkdir("db") unless File.exists?("db") |
||
128 | MIDB::Interface::Server.info(:bootstrap) |
||
129 | end |
||
130 | end |
||
131 | |||
132 | # $ midb set |
||
133 | # |
||
134 | # Set the config for the project. |
||
135 | # Check syntax |
||
136 | def do_set() |
||
137 | MIDB::Interface::Errors.die(:syntax) if @args.length < 2 |
||
138 | subset = @args[1].split(":")[0] |
||
139 | subcmd = @args[1].split(":")[1] |
||
140 | set = @args.length < 3 ? false : true |
||
141 | setter = @args[2] if set |
||
142 | case subset |
||
143 | when "db" |
||
144 | # DB Config |
||
145 | case subcmd |
||
146 | when "engine" |
||
147 | if set |
||
148 | @config["dbengine"] = case setter.downcase |
||
149 | when "sqlite3" then :sqlite3 |
||
150 | when "mysql" then :mysql |
||
151 | else :undef |
||
152 | end |
||
153 | if @config["dbengine"] == :undef |
||
154 | MIDB::Interface::Errors.die(:unsupported_engine) |
||
155 | @config["dbengine"] = :sqlite3 |
||
156 | end |
||
157 | end |
||
158 | MIDB::Interface::Server.out_config(:dbengine, @config) |
||
159 | when "host" |
||
160 | @config["dbhost"] = setter if set |
||
161 | MIDB::Interface::Server.out_config(:dbhost, @config) |
||
162 | when "port" |
||
163 | @config["dbport"] = setter if set |
||
164 | MIDB::Interface::Server.out_config(:dbport, @config) |
||
165 | when "user" |
||
166 | @config["dbuser"] = setter if set |
||
167 | MIDB::Interface::Server.out_config(:dbuser, @config) |
||
168 | when "password" |
||
169 | @config["dbpassword"] = setter if set |
||
170 | MIDB::Interface::Server.out_config(:dbpassword, @config) |
||
171 | else |
||
172 | MIDB::Interface::Errors.die(:syntax) |
||
173 | end |
||
174 | when "api" |
||
175 | case subcmd |
||
176 | when "key" |
||
177 | @config["apikey"] = setter if set |
||
178 | MIDB::Interface::Server.out_config(:apikey, @config) |
||
179 | when "getkey" |
||
180 | if setter == "nil" |
||
181 | @config["apigetkey"] = nil if set |
||
182 | else |
||
183 | @config["apigetkey"] = setter if set |
||
184 | end |
||
185 | MIDB::Interface::Server.out_config(:apigetkey, @config) |
||
186 | end |
||
187 | when "privacy" |
||
188 | case subcmd |
||
189 | when "get" |
||
190 | @config["privacyget"] = self.to_bool(setter) if set |
||
191 | MIDB::Interface::Server.out_config(:privacyget, @config) |
||
192 | when "post" |
||
193 | @config["privacypost"] = self.to_bool(setter) if set |
||
194 | MIDB::Interface::Server.out_config(:privacypost, @config) |
||
195 | when "put" |
||
196 | @config["privacyput"] = self.to_bool(setter) if set |
||
197 | MIDB::Interface::Server.out_config(:privacyput, @config) |
||
198 | when "delete" |
||
199 | @config["privacydelete"] = self.to_bool(setter) if set |
||
200 | MIDB::Interface::Server.out_config(:privacydelete, @config) |
||
201 | else |
||
202 | MIDB::Interface::Errors.die(:syntax) |
||
203 | end |
||
204 | else |
||
205 | MIDB::Interface::Errors.die(:syntax) |
||
206 | end |
||
207 | end |
||
208 | |||
209 | # $ midb start |
||
210 | # |
||
211 | # Start the server (call the loop) |
||
212 | def do_start() |
||
213 | # Check syntax |
||
214 | MIDB::Interface::Errors.die(:syntax) if @args.length < 2 |
||
215 | MMIDB::Interface::Errors.die(:syntax) if @args[1].split(":")[0] != "db" |
||
216 | # Is the server already started? |
||
217 | MIDB::Interface::Errors.die(:server_already_started) if @config["status"] == :running |
||
218 | # Are any files being served? |
||
219 | MIDB::Interface::Errors.die(:no_serves) if @config["serves"].length == 0 |
||
220 | # If it successfully starts, change our status and notify thru view |
||
221 | @args.each do |arg| |
||
222 | if arg.split(":")[0] == "db" |
||
223 | @db = arg.split(":")[1] |
||
224 | elsif arg.split(":")[0] == "port" |
||
225 | @port = arg.split(":")[1] |
||
226 | end |
||
227 | end |
||
228 | |||
229 | # Call the server engine and supply the (non)existing hooks |
||
230 | eng = MIDB::API::Engine.new(@db, @http_status, @config, @hooks) |
||
231 | if eng.start(@port) |
||
232 | @config["status"] = :running |
||
233 | MIDB::Interface::Server.success() |
||
234 | else |
||
235 | MIDB::Interface::Errors.die(:server_error) |
||
236 | end |
||
237 | end |
||
238 | |||
239 | # $ midb serve |
||
240 | # |
||
241 | # Serve a JSON file |
||
242 | def do_serve() |
||
243 | # Check if there's a second argument |
||
244 | MIDB::Interface::Errors.die(:syntax) if @args.length < 2 |
||
245 | # Is the server running? It shouldn't |
||
246 | MIDB::Interface::Errors.die(:server_already_started) if @config["status"] == :running |
||
247 | # Is there such file as @args[1]? |
||
248 | MIDB::Interface::Errors.die(:file_404) unless File.file?("./json/" + @args[1]) |
||
249 | # Is the file a JSON file? |
||
250 | MMIDB::Interface::Errors.die(:not_json) unless File.extname(@args[1]) == ".json" |
||
251 | # Is the file already loaded? |
||
252 | MIDB::Interface::Errors.die(:json_exists) if @config["serves"].include? @args[1] |
||
253 | |||
254 | # Tests passed, so let's add the file to the served list! |
||
255 | @config["serves"].push @args[1] |
||
256 | MIDB::Interface::Server.show_serving(@config) |
||
257 | end |
||
258 | |||
259 | # $ midb unserve |
||
260 | # |
||
261 | # Stop serving a JSON file |
||
262 | def self.do_unserve() |
||
263 | # Check if there's a second argument |
||
264 | MIDB::Interface::Errors.die(:syntax) if @args.length < 2 |
||
265 | # Is the server running? It shouldn't |
||
266 | MIDB::Interface::Errors.die(:server_already_started) if @config["status"] == :running |
||
267 | # Is the file already loaded? |
||
268 | MIDB::Interface::Errors.die(:json_not_exists) unless @config["serves"].include? @args[1] |
||
269 | |||
270 | # Delete it! |
||
271 | @config["serves"].delete @args[1] |
||
272 | MIDB::Interface::Server.show_serving(@config) |
||
273 | end |
||
274 | |||
275 | # $ midb stop |
||
276 | # |
||
277 | # Stop the server in case it's running in the background. |
||
278 | def do_stop() |
||
279 | # Is the server running? |
||
280 | MIDB::Interface::Errors.die(:server_not_running) unless @config["status"] == :running |
||
281 | |||
282 | @config["status"] = :asleep |
||
283 | MIDB::Interface::Server.server_stopped() |
||
284 | end |
||
285 | |||
286 | |||
287 | |||
288 | # $ midb |
||
289 | # |
||
290 | # Decide the behavior of the server in function of the arguments. |
||
291 | def init() |
||
292 | # We should have at least one argument, which can be `run` or `serve` |
||
293 | MIDB::Interface::Errors.die(:noargs) if @args.length < 1 |
||
294 | |||
295 | # Load the config |
||
296 | if File.file?(".midb.yaml") |
||
297 | @config = YAML.load_file(".midb.yaml") |
||
298 | else |
||
299 | # If the file doesn't exist, we need to bootstrap |
||
300 | MIDB::Interface::Errors.die(:bootstrap) if @args[0] != "help" && args[0] != "bootstrap" |
||
301 | end |
||
302 | |||
303 | case @args[0] |
||
304 | |||
305 | # Command: help |
||
306 | when "help" |
||
307 | self.do_help() |
||
308 | |||
309 | # Command: bootstrap |
||
310 | when "bootstrap" |
||
311 | self.do_bootstrap() |
||
312 | |||
313 | # Command: set |
||
314 | when "set" |
||
315 | self.do_set() |
||
316 | |||
317 | |||
318 | # Command: start |
||
319 | when "start" |
||
320 | self.do_start() |
||
321 | |||
322 | # Command: serve |
||
323 | # Serves a JSON file |
||
324 | when "serve" |
||
325 | self.do_serve() |
||
326 | |||
327 | # Command: unserve |
||
328 | # Stop serving a JSON file. |
||
329 | when "unserve" |
||
330 | self.do_unserve() |
||
331 | |||
332 | # Command: stop |
||
333 | # Stops the server. |
||
334 | when "stop" |
||
335 | self.do_stop() |
||
336 | end |
||
337 | end |
||
338 | |||
339 | # Method: save |
||
340 | # Saves config to .midb.yaml |
||
341 | def save() |
||
342 | File.open(".midb.yaml", 'w') do |l| |
||
343 | l.write @config.to_yaml |
||
344 | end |
||
345 | end |
||
346 | end |
||
348 | end |