- Notifications
You must be signed in to change notification settings - Fork5
chore: use slim binary over dylib#210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -10,3 +10,5 @@ type_name: | ||
identifier_name: | ||
allowed_symbols: "_" | ||
min_length: 1 | ||
line_length: | ||
ignores_urls: true |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -7,26 +7,56 @@ actor Manager { | ||
let cfg: ManagerConfig | ||
let telemetryEnricher: TelemetryEnricher | ||
lettunnelDaemon: TunnelDaemon | ||
let speaker: Speaker<Vpn_ManagerMessage, Vpn_TunnelMessage> | ||
var readLoop: Task<Void, any Error>! | ||
#if arch(arm64) | ||
private static let binaryName = "coder-darwin-arm64" | ||
#else | ||
private static let binaryName = "coder-darwin-amd64" | ||
#endif | ||
// /var/root/Library/Application Support/com.coder.Coder-Desktop/coder-darwin-{arm64,amd64} | ||
private let dest = try? FileManager.default | ||
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true) | ||
.appendingPathComponent(Bundle.main.bundleIdentifier ?? "com.coder.Coder-Desktop", isDirectory: true) | ||
.appendingPathComponent(binaryName) | ||
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "manager") | ||
// swiftlint:disable:next function_body_length | ||
init(cfg: ManagerConfig) async throws(ManagerError) { | ||
self.cfg = cfg | ||
telemetryEnricher = TelemetryEnricher() | ||
guard let dest else { | ||
// This should never happen | ||
throw .fileError("Failed to create path for binary destination" + | ||
"(/var/root/Library/Application Support/com.coder.Coder-Desktop)") | ||
} | ||
do { | ||
try FileManager.default.ensureDirectories(for: dest) | ||
} catch { | ||
throw .fileError( | ||
"Failed to create directories for binary destination (\(dest)): \(error.localizedDescription)" | ||
) | ||
} | ||
let client = Client(url: cfg.serverUrl) | ||
let buildInfo: BuildInfoResponse | ||
do { | ||
buildInfo = try await client.buildInfo() | ||
} catch { | ||
throw .serverInfo(error.description) | ||
} | ||
guard let serverSemver = buildInfo.semver else { | ||
throw .serverInfo("invalid version: \(buildInfo.version)") | ||
} | ||
guard Validator.minimumCoderVersion | ||
.compare(serverSemver, options: .numeric) != .orderedDescending | ||
else { | ||
throw .belowMinimumCoderVersion(actualVersion: serverSemver) | ||
} | ||
let binaryPath = cfg.serverUrl.appending(path: "bin").appending(path: Manager.binaryName) | ||
do { | ||
let sessionConfig = URLSessionConfiguration.default | ||
// The tunnel might be asked to start before the network interfaces have woken up from sleep | ||
@@ -35,7 +65,7 @@ actor Manager { | ||
sessionConfig.timeoutIntervalForRequest = 60 | ||
sessionConfig.timeoutIntervalForResource = 300 | ||
try await download( | ||
src:binaryPath, | ||
dest: dest, | ||
urlSession: URLSession(configuration: sessionConfig) | ||
) { progress in | ||
@@ -45,48 +75,46 @@ actor Manager { | ||
throw .download(error) | ||
} | ||
pushProgress(stage: .validating) | ||
do { | ||
tryValidator.validate(path: dest) | ||
} catch { | ||
// Cleanup unvalid binary | ||
try? FileManager.default.removeItem(at: dest) | ||
throw .validation(error) | ||
} | ||
// Without this, the TUN fd isn't recognised as a socket in the | ||
// spawned process, and the tunnel fails to start. | ||
do { | ||
tryunsetCloseOnExec(fd: cfg.tunFd) | ||
} catch { | ||
throw .cloexec(error) | ||
} | ||
do { | ||
try tunnelDaemon = await TunnelDaemon(binaryPath: dest) { err in | ||
Task { try? await NEXPCServerDelegate.cancelProvider(error: | ||
makeNSError(suffix: "TunnelDaemon", desc: "Tunnel daemon: \(err.description)") | ||
) } | ||
} | ||
} catch { | ||
throw .tunnelSetup(error) | ||
} | ||
speaker = await Speaker<Vpn_ManagerMessage, Vpn_TunnelMessage>( | ||
writeFD:tunnelDaemon.writeHandle, | ||
readFD:tunnelDaemon.readHandle | ||
) | ||
do { | ||
try await speaker.handshake() | ||
} catch { | ||
throw .handshake(error) | ||
} | ||
readLoop = Task { try await run() } | ||
} | ||
deinit { logger.debug("manager deinit") } | ||
func run() async throws { | ||
do { | ||
for try await m in speaker { | ||
@@ -99,14 +127,14 @@ actor Manager { | ||
} | ||
} catch { | ||
logger.error("tunnel read loop failed: \(error.localizedDescription, privacy: .public)") | ||
try awaittunnelDaemon.close() | ||
try await NEXPCServerDelegate.cancelProvider(error: | ||
makeNSError(suffix: "Manager", desc: "Tunnel read loop failed: \(error.localizedDescription)") | ||
) | ||
return | ||
} | ||
logger.info("tunnel read loop exited") | ||
try awaittunnelDaemon.close() | ||
try await NEXPCServerDelegate.cancelProvider(error: nil) | ||
} | ||
@@ -204,6 +232,12 @@ actor Manager { | ||
if !stopResp.success { | ||
throw .errorResponse(msg: stopResp.errorMessage) | ||
} | ||
do { | ||
try await tunnelDaemon.close() | ||
} catch { | ||
throw .tunnelFail(error) | ||
} | ||
readLoop.cancel() | ||
} | ||
// Retrieves the current state of all peers, | ||
@@ -239,28 +273,32 @@ struct ManagerConfig { | ||
enum ManagerError: Error { | ||
case download(DownloadError) | ||
case fileError(String) | ||
case tunnelSetup(TunnelDaemonError) | ||
case handshake(HandshakeError) | ||
case validation(ValidationError) | ||
case incorrectResponse(Vpn_TunnelMessage) | ||
case cloexec(POSIXError) | ||
case failedRPC(any Error) | ||
case serverInfo(String) | ||
case errorResponse(msg: String) | ||
case tunnelFail(any Error) | ||
case belowMinimumCoderVersion(actualVersion: String) | ||
var description: String { | ||
switch self { | ||
case let .download(err): | ||
"Download error: \(err.localizedDescription)" | ||
case let .fileError(msg): | ||
msg | ||
case let .tunnelSetup(err): | ||
"Tunnel setup error: \(err.localizedDescription)" | ||
case let .handshake(err): | ||
"Handshake error: \(err.localizedDescription)" | ||
case let .validation(err): | ||
"Validation error: \(err.localizedDescription)" | ||
case let .cloexec(err): | ||
"Failed to mark TUN fd as non-cloexec: \(err.localizedDescription)" | ||
case .incorrectResponse: | ||
"Received unexpected response over tunnel" | ||
case let .failedRPC(err): | ||
@@ -269,14 +307,13 @@ enum ManagerError: Error { | ||
msg | ||
case let .errorResponse(msg): | ||
msg | ||
case let .tunnelFail(err): | ||
"Failed to communicate with daemon over tunnel: \(err.localizedDescription)" | ||
case let .belowMinimumCoderVersion(actualVersion): | ||
""" | ||
The Coder deployment must be version \(Validator.minimumCoderVersion) | ||
or higher to use Coder Desktop. Current version: \(actualVersion) | ||
ethanndickson marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
""" | ||
} | ||
} | ||
@@ -297,9 +334,16 @@ func writeVpnLog(_ log: Vpn_Log) { | ||
case .UNRECOGNIZED: .info | ||
} | ||
let logger = Logger( | ||
subsystem: "\(Bundle.main.bundleIdentifier!).daemon", | ||
category: log.loggerNames.joined(separator: ".") | ||
) | ||
let fields = log.fields.map { "\($0.name): \($0.value)" }.joined(separator: ", ") | ||
logger.log(level: level, "\(log.message, privacy: .public)\(fields.isEmpty ? "" : ": \(fields)", privacy: .public)") | ||
} | ||
extension FileManager { | ||
func ensureDirectories(for url: URL) throws { | ||
let dir = url.hasDirectoryPath ? url : url.deletingLastPathComponent() | ||
try createDirectory(at: dir, withIntermediateDirectories: true, attributes: nil) | ||
} | ||
} |
This file was deleted.
Uh oh!
There was an error while loading.Please reload this page.
This file was deleted.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.