aboutsummaryrefslogtreecommitdiff
path: root/Sources/server.swift
blob: c8cf97b3636fb4259bfde3e24794606df452797e (plain)
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
// The Swift Programming Language
// https://docs.swift.org/swift-book

import ArgumentParser
import Foundation
import Logging
import NIO

@main
struct swiftGopher: ParsableCommand {
  @Option(name: [.short, .long], help: "Hostname used for generating selectors")
  var gopherHostName: String = "localhost"
  @Option(name: [.short, .long])
  var host: String = "0.0.0.0"
  @Option(name: [.short, .long])
  var port: Int = 8080
  @Option(name: [.customShort("d"), .long], help: "Data directory to map")
  var gopherDataDir: String = "./example-gopherdata"
  @Flag(help: "Disable full-text search feature") 
  var disableSearch: Bool = false
  @Flag(help: "Disable reading gophermap files to override automatic generation")
  var disableGophermap: Bool = false

  public mutating func run() throws {
    let eventLoopGroup = MultiThreadedEventLoopGroup(
      numberOfThreads: System.coreCount
    )

    defer {
      try! eventLoopGroup.syncShutdownGracefully()
    }

    let localGopherDataDir = gopherDataDir
    let localGopherHostName = gopherHostName
    let localPort = port
    let localEnableSearch = !disableSearch
    let localDisableGophermap = disableGophermap

    let logger = Logger(label: "com.navanchauhan.gopher.server")

    let serverBootstrap = ServerBootstrap(
      group: eventLoopGroup
    )
    .serverChannelOption(
      ChannelOptions.backlog,
      value: 256
    )
    .serverChannelOption(
      ChannelOptions.socketOption(
        .so_reuseaddr
      ),
      value: 1
    )
    .childChannelInitializer { channel in
      channel.pipeline.addHandlers([
        BackPressureHandler(),
        GopherHandler(
          logger: logger,
          gopherdata_dir: localGopherDataDir,
          gopherdata_host: localGopherHostName,
          gopherdata_port: localPort,
          enableSearch: localEnableSearch,
          disableGophermap: localDisableGophermap
        ),
      ])
    }
    .childChannelOption(
      ChannelOptions.socketOption(
        .so_reuseaddr
      ),
      value: 1
    )
    .childChannelOption(
      ChannelOptions.maxMessagesPerRead,
      value: 16
    )
    .childChannelOption(
      ChannelOptions.recvAllocator,
      value: AdaptiveRecvByteBufferAllocator()
    )

    let defaultHost = host
    let defaultPort = port

    let channel = try serverBootstrap.bind(
      host: defaultHost,
      port: defaultPort
    ).wait()

    logger.info("Server started and listening on \(channel.localAddress!)")
    try channel.closeFuture.wait()
    logger.info("Server closed")
  }
}