Controller.do_start()   B
last analyzed

Complexity

Conditions 6

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 6
dl 0
loc 26
rs 7.5384
1
require 'midb/server_model'
2
require 'midb/server_view'
3
require 'midb/errors_view'
4
require 'midb/security_controller'
5
require 'midb/serverengine_controller'
6
require 'midb/hooks'
7
8
require 'yaml'
9
require 'socket'
10
require 'uri'
11
require 'json'
12
require 'sqlite3'
13
14
module MIDB
15
  module API
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
347
  end
348
end