|
1 |
| -import ArgumentParsing |
2 |
| -import GitHubAPI |
| 1 | +import ArgumentParser |
3 | 2 | import HTTPServer
|
4 | 3 | import MongoDB
|
5 | 4 | import NIOPosix
|
6 | 5 | import NIOSSL
|
| 6 | +import System_ArgumentParser |
7 | 7 | import System
|
8 | 8 | import UnidocServer
|
9 | 9 |
|
10 | 10 | extension Unidoc
|
11 | 11 | {
|
12 | 12 | struct Preview
|
13 | 13 | {
|
14 |
| - var certificates:String |
15 |
| - |
16 |
| - var development:Unidoc.ServerOptions.Development |
17 |
| - var mirror:Bool |
18 |
| - var https:Bool |
19 |
| - var mongo:Mongo.Host |
20 |
| - |
21 |
| - private |
22 |
| - init() throws |
| 14 | + @Option( |
| 15 | + name: [.customLong("certificates"), .customShort("c")], |
| 16 | + help: "A path to the certificates directory", |
| 17 | + completion: .directory) |
| 18 | + var certificates:FilePath.Directory = "Assets/certificates" |
| 19 | + |
| 20 | + @Option( |
| 21 | + name: [.customLong("mongo"), .customShort("m")], |
| 22 | + help: "The name of a host running mongod to connect to, and optionally, the port") |
| 23 | + var mongod:Mongo.Host = "localhost" |
| 24 | + |
| 25 | + @Option( |
| 26 | + name: [.customLong("replica-set"), .customShort("s")], |
| 27 | + help: "The name of a replica set to connect to") |
| 28 | + var replicaSet:String = "unidoc-rs" |
| 29 | + |
| 30 | + @Option( |
| 31 | + name: [.customLong("port"), .customShort("p")], |
| 32 | + help: "The number of a port to bind the documentation server to") |
| 33 | + var port:Int? |
| 34 | + |
| 35 | + @Flag( |
| 36 | + name: [.customLong("mirror"), .customShort("q")], |
| 37 | + help: "Run in mirror mode, disabling the documentation linker process") |
| 38 | + var mirror:Bool = false |
| 39 | + |
| 40 | + @Flag( |
| 41 | + name: [.customLong("https"), .customShort("e")], |
| 42 | + help: "Use https instead of http") |
| 43 | + var https:Bool = false |
| 44 | + |
| 45 | + init() |
23 | 46 | {
|
24 |
| - self.certificates = "Assets/certificates" |
25 |
| - self.development = .init() |
26 |
| - self.development.port = 8080 |
27 |
| - self.mirror = false |
28 |
| - self.https = false |
29 |
| - self.mongo = "localhost" |
30 | 47 | }
|
31 | 48 | }
|
32 | 49 | }
|
33 | 50 | extension Unidoc.Preview
|
34 | 51 | {
|
35 |
| - private mutating |
36 |
| - func parse() throws |
| 52 | + private |
| 53 | + var serverSSL:NIOSSLContext |
37 | 54 | {
|
38 |
| - var arguments:CommandLine.Arguments = .init() |
39 |
| - |
40 |
| - while let argument:String = arguments.next() |
| 55 | + get throws |
41 | 56 | {
|
42 |
| - switch argument |
43 |
| - { |
44 |
| - case "-c", "--certificates": |
45 |
| - self.certificates = try arguments.next(for: "certificates") |
| 57 | + let privateKeyPath:FilePath = self.certificates / "privkey.pem" |
| 58 | + let privateKey:NIOSSLPrivateKey = try .init(file: "\(privateKeyPath)", format: .pem) |
46 | 59 |
|
47 |
| - case "-q", "--mirror": |
48 |
| - self.mirror = true |
| 60 | + let fullChainPath:FilePath = self.certificates / "fullchain.pem" |
| 61 | + let fullChain:[NIOSSLCertificate] = try NIOSSLCertificate.fromPEMFile( |
| 62 | + "\(fullChainPath)") |
49 | 63 |
|
50 |
| - case "-s", "--replica-set": |
51 |
| - self.development.replicaSet = try arguments.next(for: "replica-set") |
52 |
| - |
53 |
| - case "-e", "--https": |
54 |
| - self.https = true |
55 |
| - self.development.port = 8443 |
56 |
| - |
57 |
| - case "-m", "--mongo": |
58 |
| - self.mongo = .init(try arguments.next(for: "mongo")) |
| 64 | + var configuration:TLSConfiguration = .makeServerConfiguration( |
| 65 | + certificateChain: fullChain.map(NIOSSLCertificateSource.certificate(_:)), |
| 66 | + privateKey: .privateKey(privateKey)) |
59 | 67 |
|
60 |
| - case "-p", "--port": |
61 |
| - self.https = true |
62 |
| - self.development.port = try arguments.next(for: "port") |
| 68 | + // configuration.applicationProtocols = ["h2", "http/1.1"] |
| 69 | + configuration.applicationProtocols = ["h2"] |
63 | 70 |
|
64 |
| - case let option: |
65 |
| - throw CommandLine.ArgumentError.unknown(option) |
66 |
| - } |
| 71 | + return try .init(configuration: configuration) |
67 | 72 | }
|
68 | 73 | }
|
69 |
| -} |
70 | 74 |
|
71 |
| -@main |
72 |
| -extension Unidoc.Preview |
73 |
| -{ |
74 |
| - static |
75 |
| - func main() async throws |
| 75 | + private |
| 76 | + var clientSSL:NIOSSLContext |
76 | 77 | {
|
77 |
| - var main:Self = try .init() |
78 |
| - try main.parse() |
79 |
| - try await main.launch() |
| 78 | + get throws |
| 79 | + { |
| 80 | + var configuration:TLSConfiguration = .makeClientConfiguration() |
| 81 | + configuration.applicationProtocols = ["h2"] |
| 82 | + return try .init(configuration: configuration) |
| 83 | + } |
80 | 84 | }
|
81 | 85 | }
|
82 |
| -extension Unidoc.Preview |
| 86 | + |
| 87 | +@main |
| 88 | +extension Unidoc.Preview:AsyncParsableCommand |
83 | 89 | {
|
84 |
| - private consuming |
85 |
| - func options() throws -> Unidoc.ServerOptions |
| 90 | + func run() async throws |
86 | 91 | {
|
87 |
| - let authority:any HTTP.ServerAuthority |
88 |
| - if self.https |
89 |
| - { |
90 |
| - let privateKey:NIOSSLPrivateKey = |
91 |
| - try .init(file: "\(self.certificates)/privkey.pem", format: .pem) |
92 |
| - let fullChain:[NIOSSLCertificate] = |
93 |
| - try NIOSSLCertificate.fromPEMFile("\(self.certificates)/fullchain.pem") |
| 92 | + let threads:MultiThreadedEventLoopGroup = .init(numberOfThreads: 2) |
94 | 93 |
|
95 |
| - var configuration:TLSConfiguration = .makeServerConfiguration( |
96 |
| - certificateChain: fullChain.map(NIOSSLCertificateSource.certificate(_:)), |
97 |
| - privateKey: .privateKey(privateKey)) |
| 94 | + defer |
| 95 | + { |
| 96 | + try? threads.syncShutdownGracefully() |
| 97 | + } |
98 | 98 |
|
99 |
| - // configuration.applicationProtocols = ["h2", "http/1.1"] |
100 |
| - configuration.applicationProtocols = ["h2"] |
| 99 | + var development:Unidoc.ServerOptions.Development = .init(replicaSet: self.replicaSet) |
| 100 | + let authority:any HTTP.ServerAuthority |
101 | 101 |
|
102 |
| - authority = HTTP.LocalhostSecure.init( |
103 |
| - context: try .init(configuration: configuration)) |
| 102 | + if self.https |
| 103 | + { |
| 104 | + authority = HTTP.LocalhostSecure.init(context: try self.serverSSL) |
| 105 | + development.port = self.port ?? 8443 |
104 | 106 | }
|
105 | 107 | else
|
106 | 108 | {
|
107 | 109 | authority = HTTP.Localhost.init()
|
| 110 | + development.port = self.port ?? 8080 |
108 | 111 | }
|
109 | 112 |
|
110 |
| - return .init(authority: authority, |
| 113 | + let options:Unidoc.ServerOptions = .init(authority: authority, |
111 | 114 | github: nil,
|
112 | 115 | mirror: self.mirror,
|
113 | 116 | bucket: .init(
|
114 |
| - assets: self.development.bucket, |
115 |
| - graphs: self.development.bucket), |
116 |
| - mode: .development(.init(source: "Assets"), self.development)) |
117 |
| - } |
118 |
| - |
119 |
| - private consuming |
120 |
| - func launch() async throws |
121 |
| - { |
122 |
| - let threads:MultiThreadedEventLoopGroup = .init(numberOfThreads: 2) |
123 |
| - |
124 |
| - defer |
125 |
| - { |
126 |
| - try? threads.syncShutdownGracefully() |
127 |
| - } |
128 |
| - |
129 |
| - let mongod:Mongo.Host = self.mongo |
130 |
| - |
131 |
| - var configuration:TLSConfiguration = .makeClientConfiguration() |
132 |
| - configuration.applicationProtocols = ["h2"] |
| 117 | + assets: development.bucket, |
| 118 | + graphs: development.bucket), |
| 119 | + mode: .development(.init(source: "Assets"), development)) |
133 | 120 |
|
134 | 121 | let context:Unidoc.ServerPluginContext = .init(threads: threads,
|
135 |
| - niossl: try .init(configuration: configuration)) |
136 |
| - let options:Unidoc.ServerOptions = try self.options() |
| 122 | + niossl: try self.clientSSL) |
137 | 123 |
|
138 |
| - let mongodb:Mongo.DriverBootstrap = MongoDB / [mongod] /? |
| 124 | + let mongodb:Mongo.DriverBootstrap = MongoDB / [self.mongod] /? |
139 | 125 | {
|
140 | 126 | $0.executors = .shared(threads)
|
141 | 127 | $0.appname = "Unidoc Preview"
|
|
0 commit comments