oficina / sheets Public

Clone
git clone https://amadan.net/oficina/sheets

Plain git — no account needed to clone.

Download

Download this file

1#if os(macOS)
2import Foundation
3import Network
4
5final class ResizeFixtureServer: @unchecked Sendable {
6 private let listener: NWListener
7 private let queue = DispatchQueue(label: "sheets.resize.fixture")
8 private let lock = NSLock()
9 private var received: [[String: Int]] = []
10 var requests: [[String: Int]] { lock.withLock { received } }
11 init() throws { listener = try NWListener(using: .tcp, on: .any) }
12 func start() async throws -> URL {
13 listener.newConnectionHandler = { [weak self] connection in
14 guard let self else { return }
15 connection.start(queue: self.queue)
16 self.read(connection, buffer: Data())
17 }
18 return try await withCheckedThrowingContinuation { continuation in
19 listener.stateUpdateHandler = { [weak self] state in
20 guard let self else { return }
21 switch state {
22 case .ready:
23 self.listener.stateUpdateHandler = nil
24 continuation.resume(returning: URL(string: "http://127.0.0.1:\(self.listener.port!.rawValue)")!)
25 case .failed(let error):
26 self.listener.stateUpdateHandler = nil
27 continuation.resume(throwing: error)
28 default: break
29 }
30 }
31 listener.start(queue: queue)
32 }
33 }
34 func stop() { listener.cancel() }
35 private func read(_ connection: NWConnection, buffer: Data) {
36 connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { [weak self] data, _, complete, error in
37 guard let self, let data, error == nil else { connection.cancel(); return }
38 var bytes = buffer; bytes.append(data)
39 guard let separator = bytes.range(of: Data("\r\n\r\n".utf8)),
40 let headers = String(data: bytes[..<separator.lowerBound], encoding: .utf8),
41 let lengthLine = headers.components(separatedBy: "\r\n").first(where: { $0.lowercased().hasPrefix("content-length:") }),
42 let length = Int(lengthLine.split(separator: ":", maxSplits: 1)[1].trimmingCharacters(in: .whitespaces)),
43 bytes.count - separator.upperBound >= length else {
44 if !complete { self.read(connection, buffer: bytes) } else { connection.cancel() }
45 return
46 }
47 let body = bytes.subdata(in: separator.upperBound..<(separator.upperBound + length))
48 guard let request = try? JSONDecoder().decode([String: Int].self, from: body), let size = request["size"] else { connection.cancel(); return }
49 self.lock.withLock { self.received.append(request) }
50 let axis = request["col"] == nil ? "rows" : "cols"
51 let index = request["col"] ?? request["row"] ?? 0
52 let response = "{\"version\":0,\"cells\":[],\"sizes\":{\"\(axis)\":{\"\(index)\":\(size)}}}"
53 let message = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: \(response.utf8.count)\r\nConnection: close\r\n\r\n\(response)"
54 connection.send(content: Data(message.utf8), completion: .contentProcessed { _ in connection.cancel() })
55 }
56 }
57}
58#endif
59