Module: SpiderGazelle::Options

Defined in:
lib/spider-gazelle/options.rb

Constant Summary collapse

DEFAULTS =
{
    host: "0.0.0.0",
    port: 3000,
    verbose: false,
    tls: false,
    backlog: 4096,
    rackup: "#{Dir.pwd}/config.ru",
    mode: :thread,
    isolate: true
}.freeze
APP_OPTIONS =

Options that can’t be used when more than one set of options is being applied

[:port, :host, :verbose, :debug, :environment, :rackup, :mode, :backlog, :count, :name, :loglevel].freeze
MUTUALLY_EXCLUSIVE =
{

    # Only :password is valid when this option is present
    update: APP_OPTIONS

}.freeze

Class Method Summary collapse

Class Method Details

.parse(args) ⇒ Object



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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/spider-gazelle/options.rb', line 32

def self.parse(args)
    options = {}

    parser = OptionParser.new do |opts|
        # ================
        # STANDARD OPTIONS
        # ================
        opts.on "-p", "--port PORT", Integer, "Define what port TCP port to bind to (default: 3000)" do |arg|
            options[:port] = arg
        end

        opts.on "-h", "--host ADDRESS", "bind to address (default: 0.0.0.0)" do |arg|
            options[:host] = arg
        end

        opts.on "-v", "--verbose", "loud output" do
            options[:verbose] = true
        end

        opts.on "-d", "--debug", "debugging mode with lowered security and manual processes" do
            options[:debug] = true
        end

        opts.on "-e", "--environment ENVIRONMENT", "The environment to run the Rack app on (default: development)" do |arg|
            options[:environment] = arg
        end

        opts.on "-r", "--rackup FILE", "Load Rack config from this file (default: config.ru)" do |arg|
            options[:rackup] = arg
        end

        opts.on "-rl", "--rack-lint", "enable rack lint on all requests" do
            options[:lint] = true
        end

        opts.on "-m", "--mode MODE", MODES, "Either reactor, thread or inline (default: reactor)" do |arg|
            options[:mode] = arg
        end

        opts.on "-b", "--backlog BACKLOG", Integer, "Number of pending connections allowed (default: 5000)" do |arg|
            options[:backlog] = arg
        end


        # =================
        # TLS Configuration
        # =================
        opts.on "-t", "--use-tls PRIVATE_KEY_FILE", "Enables TLS on the port specified using the provided private key in PEM format" do |arg|
            options[:tls] = true
            options[:private_key] = arg
        end

        opts.on "-tc", "--tls-chain-file CERT_CHAIN_FILE", "The certificate chain to provide clients" do |arg|
            options[:cert_chain] = arg
        end

        opts.on "-ts", "--tls-ciphers CIPHER_LIST", "A list of Ciphers that the server will accept" do |arg|
            options[:ciphers] = arg
        end

        opts.on "-tv", "--tls-verify-peer", "Do we want to verify the client connections? (default: false)" do
            options[:verify_peer] = true
        end


        # ========================
        # CHILD PROCESS INDICATORS
        # ========================
        opts.on "-g", "--gazelle PASSWORD", 'For internal use only' do |arg|
            options[:gazelle] = arg
        end

        opts.on "-f", "--file IPC", 'For internal use only' do |arg|
            options[:gazelle_ipc] = arg
        end


        opts.on "-s", "--spider PASSWORD", 'For internal use only' do |arg|
            options[:spider] = arg
        end


        opts.on "-i", "--interactive-mode", 'Loads a multi-process version of spider-gazelle that can live update your app' do
            options[:isolate] = false
        end

        opts.on "-c", "--count NUMBER", Integer, "Number of gazelle processes to launch (default: number of CPU cores)" do |arg|
            options[:count] = arg
        end


        # ==================
        # SIGNALLING OPTIONS
        # ==================
        opts.on "-u", "--update", "Live migrates to a new process without dropping existing connections" do |arg|
            options[:update] = true
        end

        opts.on "-up", "--update-password PASSWORD", "Sets a password for performing updates" do |arg|
            options[:password] = arg
        end

        opts.on "-l", "--loglevel LEVEL", Logger::LEVELS, "Sets the log level" do |arg|
            options[:loglevel] = arg
        end
    end

    parser.banner = "sg <options> <rackup file>"
    parser.on_tail "-h", "--help", "Show help" do
        puts parser
        exit 1
    end
    parser.parse!(args)

    # Check for rackup file
    if args.last =~ /\.ru$/
        options[:rackup] = args.last
    end

    # Unless this is a signal then we want to include the default options
    unless options[:update]
        options = DEFAULTS.merge(options)

        unless File.exist? options[:rackup]
            abort "No rackup found at #{options[:rackup]}"
        end

        options[:environment] ||= ENV['RACK_ENV'] || 'development'
        ENV['RACK_ENV'] = options[:environment]

        # isolation and process mode don't mix
        options[:isolate] = false if options[:mode] == :process

        # Force no_ipc mode on Windows (sockets over pipes are not working in threaded mode)
        options[:mode] = :no_ipc if ::FFI::Platform.windows? && options[:mode] == :thread
    end

    options
end

.sanitize(args) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/spider-gazelle/options.rb', line 172

def self.sanitize(args)
    # Use "\0" as this character won't be used in the command
    cmdline = args.join("\0")
    components = cmdline.split("\0--", -1)

    # Ensure there is at least one component
    # (This will occur when no options are provided)
    components << String.new if components.empty?

    # Parse the commandline options
    options = []
    components.each do |app_opts|
        options << parse(app_opts.split(/\0+/))
    end

    # Check for any invalid requests
    exclusive = Set.new(MUTUALLY_EXCLUSIVE.keys)

    if options.length > 1

        # Some options can only be used by themselves
        options.each do |opt|
            keys = Set.new(opt.keys)

            if exclusive.intersect? keys
                invalid = exclusive & keys

                abort "The requested actions can only be used in isolation: #{invalid.to_a}"
            end
        end

        # Ensure there are no conflicting ports
        ports = [options[0][:port]]
        options[1..-1].each do |opt|
            # If there is a clash we'll increment the port by 1
            while ports.include? opt[:port]
                opt[:port] += 1
            end
            ports << opt[:port]
        end
    end

    options
end