-
Notifications
You must be signed in to change notification settings - Fork 35
/
Curassow.swift
109 lines (87 loc) · 3.03 KB
/
Curassow.swift
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
#if os(Linux)
import Glibc
#else
import Darwin
#endif
import Nest
import Commander
import Inquiline
extension ArgumentConvertible {
init(string: String) throws {
try self.init(parser: ArgumentParser(arguments: [string]))
}
}
class MultiOption<T : ArgumentConvertible> : ArgumentDescriptor {
typealias ValueType = [T]
let name: String
let flag: Character?
let description: String?
let `default`: ValueType
var type: ArgumentType { return .Option }
init(_ name: String, _ `default`: ValueType, flag: Character? = nil, description: String? = nil) {
self.name = name
self.flag = flag
self.description = description
self.`default` = `default`
}
func parse(parser: ArgumentParser) throws -> ValueType {
var options: ValueType = []
while let value = try parser.shiftValueForOption(name) {
let value = try T(string: value)
options.append(value)
}
if let flag = flag {
while let value = try parser.shiftValueForFlag(flag) {
let value = try T(string: value)
options.append(value)
}
}
if options.isEmpty {
return `default`
}
return options
}
}
func getIntEnv(key: String, `default`: Int) -> Int {
let value = getenv(key)
if value != nil {
if let stringValue = String.fromCString(value), intValue = Int(stringValue) {
return intValue
}
}
return `default`
}
struct ServeError : ErrorType, CustomStringConvertible {
let description: String
init(_ description: String) {
self.description = description
}
}
@noreturn public func serve(closure: RequestType -> ResponseType) {
let port = UInt16(getIntEnv("PORT", default: 8000))
let workers = getIntEnv("WEB_CONCURRENCY", default: 1)
command(
Option("worker-type", "sync"),
Option("workers", workers, description: "The number of processes for handling requests."),
MultiOption("bind", [Address.IP(hostname: "0.0.0.0", port: port)], description: "The address to bind sockets."),
Option("timeout", 30, description: "Amount of seconds to wait on a worker without activity before killing and restarting the worker."),
Flag("daemon", description: "Detaches the server from the controlling terminal and enter the background.")
) { workerType, workers, addresses, timeout, daemonize in
var configuration = Configuration()
configuration.addresses = addresses
configuration.timeout = timeout
if workerType == "synchronous" || workerType == "sync" {
let arbiter = Arbiter<SynchronousWorker>(configuration: configuration, workers: workers, application: closure)
try arbiter.run(daemonize: daemonize)
} else if workerType == "dispatch" || workerType == "gcd" {
#if os(OSX)
let arbiter = Arbiter<DispatchWorker>(configuration: configuration, workers: workers, application: closure)
try arbiter.run(daemonize: daemonize)
#else
throw ServeError("The dispatch worker is only supported on OS X")
#endif
} else {
throw ArgumentError.InvalidType(value: workerType, type: "worker type", argument: "worker-type")
}
}.run()
}