Compare commits
2 commits
72b7f1467b
...
1da00ecdf3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1da00ecdf3 | ||
|
|
baf1408060 |
11 changed files with 1783 additions and 80 deletions
|
|
@ -42,8 +42,8 @@
|
||||||
D0D4E5A62C8D9E65007F820A /* BurrowCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5312C8D996F007F820A /* BurrowCore.framework */; };
|
D0D4E5A62C8D9E65007F820A /* BurrowCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5312C8D996F007F820A /* BurrowCore.framework */; };
|
||||||
D0F4FAD32C8DC79C0068730A /* BurrowCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5312C8D996F007F820A /* BurrowCore.framework */; };
|
D0F4FAD32C8DC79C0068730A /* BurrowCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5312C8D996F007F820A /* BurrowCore.framework */; };
|
||||||
D0F7594E2C8DAB6B00126CF3 /* GRPC in Frameworks */ = {isa = PBXBuildFile; productRef = D078F7E02C8DA375008A8CEC /* GRPC */; };
|
D0F7594E2C8DAB6B00126CF3 /* GRPC in Frameworks */ = {isa = PBXBuildFile; productRef = D078F7E02C8DA375008A8CEC /* GRPC */; };
|
||||||
D0F759612C8DB24B00126CF3 /* grpc-swift-config.json in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4962C8D921A007F820A /* grpc-swift-config.json */; };
|
D0FA10012D10200100112233 /* burrow.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA10032D10200100112233 /* burrow.pb.swift */; };
|
||||||
D0F759622C8DB24B00126CF3 /* swift-protobuf-config.json in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4972C8D921A007F820A /* swift-protobuf-config.json */; };
|
D0FA10022D10200100112233 /* burrow.grpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA10042D10200100112233 /* burrow.grpc.swift */; };
|
||||||
D0F7597E2C8DB30500126CF3 /* CGRPCZlib in Frameworks */ = {isa = PBXBuildFile; productRef = D0F7597D2C8DB30500126CF3 /* CGRPCZlib */; };
|
D0F7597E2C8DB30500126CF3 /* CGRPCZlib in Frameworks */ = {isa = PBXBuildFile; productRef = D0F7597D2C8DB30500126CF3 /* CGRPCZlib */; };
|
||||||
D0F7598D2C8DB3DA00126CF3 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4992C8D921A007F820A /* Client.swift */; };
|
D0F7598D2C8DB3DA00126CF3 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4992C8D921A007F820A /* Client.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
@ -154,8 +154,6 @@
|
||||||
D0BCC6032A09535900AD070D /* libburrow.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libburrow.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
D0BCC6032A09535900AD070D /* libburrow.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libburrow.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D0BF09582C8E6789000D8DEC /* UI.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = UI.xcconfig; sourceTree = "<group>"; };
|
D0BF09582C8E6789000D8DEC /* UI.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = UI.xcconfig; sourceTree = "<group>"; };
|
||||||
D0D4E4952C8D921A007F820A /* burrow.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = burrow.proto; sourceTree = "<group>"; };
|
D0D4E4952C8D921A007F820A /* burrow.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = burrow.proto; sourceTree = "<group>"; };
|
||||||
D0D4E4962C8D921A007F820A /* grpc-swift-config.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "grpc-swift-config.json"; sourceTree = "<group>"; };
|
|
||||||
D0D4E4972C8D921A007F820A /* swift-protobuf-config.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "swift-protobuf-config.json"; sourceTree = "<group>"; };
|
|
||||||
D0D4E4992C8D921A007F820A /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
|
D0D4E4992C8D921A007F820A /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
|
||||||
D0D4E49A2C8D921A007F820A /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = "<group>"; };
|
D0D4E49A2C8D921A007F820A /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = "<group>"; };
|
||||||
D0D4E49E2C8D921A007F820A /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = "<group>"; };
|
D0D4E49E2C8D921A007F820A /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -179,6 +177,8 @@
|
||||||
D0D4E58E2C8D9D0A007F820A /* Constants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = "<group>"; };
|
D0D4E58E2C8D9D0A007F820A /* Constants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = "<group>"; };
|
||||||
D0D4E58F2C8D9D0A007F820A /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
D0D4E58F2C8D9D0A007F820A /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||||
D0D4E5902C8D9D0A007F820A /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
D0D4E5902C8D9D0A007F820A /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
||||||
|
D0FA10032D10200100112233 /* burrow.pb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Generated/burrow.pb.swift; sourceTree = "<group>"; };
|
||||||
|
D0FA10042D10200100112233 /* burrow.grpc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Generated/burrow.grpc.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
|
@ -317,8 +317,8 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D0D4E4952C8D921A007F820A /* burrow.proto */,
|
D0D4E4952C8D921A007F820A /* burrow.proto */,
|
||||||
D0D4E4962C8D921A007F820A /* grpc-swift-config.json */,
|
D0FA10032D10200100112233 /* burrow.pb.swift */,
|
||||||
D0D4E4972C8D921A007F820A /* swift-protobuf-config.json */,
|
D0FA10042D10200100112233 /* burrow.grpc.swift */,
|
||||||
);
|
);
|
||||||
path = Client;
|
path = Client;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -428,8 +428,6 @@
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
D0F7598A2C8DB34200126CF3 /* PBXTargetDependency */,
|
D0F7598A2C8DB34200126CF3 /* PBXTargetDependency */,
|
||||||
D0F7595E2C8DB24400126CF3 /* PBXTargetDependency */,
|
|
||||||
D0F759602C8DB24400126CF3 /* PBXTargetDependency */,
|
|
||||||
);
|
);
|
||||||
name = Core;
|
name = Core;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
|
|
@ -617,8 +615,8 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
D0F759612C8DB24B00126CF3 /* grpc-swift-config.json in Sources */,
|
D0FA10012D10200100112233 /* burrow.pb.swift in Sources */,
|
||||||
D0F759622C8DB24B00126CF3 /* swift-protobuf-config.json in Sources */,
|
D0FA10022D10200100112233 /* burrow.grpc.swift in Sources */,
|
||||||
D0F7598D2C8DB3DA00126CF3 /* Client.swift in Sources */,
|
D0F7598D2C8DB3DA00126CF3 /* Client.swift in Sources */,
|
||||||
D0D4E56B2C8D9C2F007F820A /* Logging.swift in Sources */,
|
D0D4E56B2C8D9C2F007F820A /* Logging.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
|
@ -689,14 +687,6 @@
|
||||||
target = D0D4E5302C8D996F007F820A /* Core */;
|
target = D0D4E5302C8D996F007F820A /* Core */;
|
||||||
targetProxy = D0F4FAD12C8DC7960068730A /* PBXContainerItemProxy */;
|
targetProxy = D0F4FAD12C8DC7960068730A /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
D0F7595E2C8DB24400126CF3 /* PBXTargetDependency */ = {
|
|
||||||
isa = PBXTargetDependency;
|
|
||||||
productRef = D0F7595D2C8DB24400126CF3 /* GRPCSwiftPlugin */;
|
|
||||||
};
|
|
||||||
D0F759602C8DB24400126CF3 /* PBXTargetDependency */ = {
|
|
||||||
isa = PBXTargetDependency;
|
|
||||||
productRef = D0F7595F2C8DB24400126CF3 /* SwiftProtobufPlugin */;
|
|
||||||
};
|
|
||||||
D0F7598A2C8DB34200126CF3 /* PBXTargetDependency */ = {
|
D0F7598A2C8DB34200126CF3 /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
productRef = D0F759892C8DB34200126CF3 /* GRPC */;
|
productRef = D0F759892C8DB34200126CF3 /* GRPC */;
|
||||||
|
|
@ -921,16 +911,6 @@
|
||||||
package = D0B1D10E2C436152004B7823 /* XCRemoteSwiftPackageReference "swift-async-algorithms" */;
|
package = D0B1D10E2C436152004B7823 /* XCRemoteSwiftPackageReference "swift-async-algorithms" */;
|
||||||
productName = AsyncAlgorithms;
|
productName = AsyncAlgorithms;
|
||||||
};
|
};
|
||||||
D0F7595D2C8DB24400126CF3 /* GRPCSwiftPlugin */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = D0D4E4822C8D8EF6007F820A /* XCRemoteSwiftPackageReference "grpc-swift" */;
|
|
||||||
productName = "plugin:GRPCSwiftPlugin";
|
|
||||||
};
|
|
||||||
D0F7595F2C8DB24400126CF3 /* SwiftProtobufPlugin */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = D0D4E4852C8D8F29007F820A /* XCRemoteSwiftPackageReference "swift-protobuf" */;
|
|
||||||
productName = "plugin:SwiftProtobufPlugin";
|
|
||||||
};
|
|
||||||
D0F7597D2C8DB30500126CF3 /* CGRPCZlib */ = {
|
D0F7597D2C8DB30500126CF3 /* CGRPCZlib */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = D0D4E4822C8D8EF6007F820A /* XCRemoteSwiftPackageReference "grpc-swift" */;
|
package = D0D4E4822C8D8EF6007F820A /* XCRemoteSwiftPackageReference "grpc-swift" */;
|
||||||
|
|
|
||||||
761
Apple/Core/Client/Generated/burrow.grpc.swift
Normal file
761
Apple/Core/Client/Generated/burrow.grpc.swift
Normal file
|
|
@ -0,0 +1,761 @@
|
||||||
|
//
|
||||||
|
// DO NOT EDIT.
|
||||||
|
// swift-format-ignore-file
|
||||||
|
//
|
||||||
|
// Generated by the protocol buffer compiler.
|
||||||
|
// Source: burrow.proto
|
||||||
|
//
|
||||||
|
import GRPC
|
||||||
|
import NIO
|
||||||
|
import NIOConcurrencyHelpers
|
||||||
|
import SwiftProtobuf
|
||||||
|
|
||||||
|
|
||||||
|
/// Usage: instantiate `Burrow_TunnelClient`, then call methods of this protocol to make API calls.
|
||||||
|
public protocol Burrow_TunnelClientProtocol: GRPCClient {
|
||||||
|
var serviceName: String { get }
|
||||||
|
var interceptors: Burrow_TunnelClientInterceptorFactoryProtocol? { get }
|
||||||
|
|
||||||
|
func tunnelConfiguration(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions?,
|
||||||
|
handler: @escaping (Burrow_TunnelConfigurationResponse) -> Void
|
||||||
|
) -> ServerStreamingCall<Burrow_Empty, Burrow_TunnelConfigurationResponse>
|
||||||
|
|
||||||
|
func tunnelStart(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> UnaryCall<Burrow_Empty, Burrow_Empty>
|
||||||
|
|
||||||
|
func tunnelStop(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> UnaryCall<Burrow_Empty, Burrow_Empty>
|
||||||
|
|
||||||
|
func tunnelStatus(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions?,
|
||||||
|
handler: @escaping (Burrow_TunnelStatusResponse) -> Void
|
||||||
|
) -> ServerStreamingCall<Burrow_Empty, Burrow_TunnelStatusResponse>
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Burrow_TunnelClientProtocol {
|
||||||
|
public var serviceName: String {
|
||||||
|
return "burrow.Tunnel"
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server streaming call to TunnelConfiguration
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - request: Request to send to TunnelConfiguration.
|
||||||
|
/// - callOptions: Call options.
|
||||||
|
/// - handler: A closure called when each response is received from the server.
|
||||||
|
/// - Returns: A `ServerStreamingCall` with futures for the metadata and status.
|
||||||
|
public func tunnelConfiguration(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil,
|
||||||
|
handler: @escaping (Burrow_TunnelConfigurationResponse) -> Void
|
||||||
|
) -> ServerStreamingCall<Burrow_Empty, Burrow_TunnelConfigurationResponse> {
|
||||||
|
return self.makeServerStreamingCall(
|
||||||
|
path: Burrow_TunnelClientMetadata.Methods.tunnelConfiguration.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeTunnelConfigurationInterceptors() ?? [],
|
||||||
|
handler: handler
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unary call to TunnelStart
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - request: Request to send to TunnelStart.
|
||||||
|
/// - callOptions: Call options.
|
||||||
|
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||||
|
public func tunnelStart(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> UnaryCall<Burrow_Empty, Burrow_Empty> {
|
||||||
|
return self.makeUnaryCall(
|
||||||
|
path: Burrow_TunnelClientMetadata.Methods.tunnelStart.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeTunnelStartInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unary call to TunnelStop
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - request: Request to send to TunnelStop.
|
||||||
|
/// - callOptions: Call options.
|
||||||
|
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||||
|
public func tunnelStop(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> UnaryCall<Burrow_Empty, Burrow_Empty> {
|
||||||
|
return self.makeUnaryCall(
|
||||||
|
path: Burrow_TunnelClientMetadata.Methods.tunnelStop.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeTunnelStopInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server streaming call to TunnelStatus
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - request: Request to send to TunnelStatus.
|
||||||
|
/// - callOptions: Call options.
|
||||||
|
/// - handler: A closure called when each response is received from the server.
|
||||||
|
/// - Returns: A `ServerStreamingCall` with futures for the metadata and status.
|
||||||
|
public func tunnelStatus(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil,
|
||||||
|
handler: @escaping (Burrow_TunnelStatusResponse) -> Void
|
||||||
|
) -> ServerStreamingCall<Burrow_Empty, Burrow_TunnelStatusResponse> {
|
||||||
|
return self.makeServerStreamingCall(
|
||||||
|
path: Burrow_TunnelClientMetadata.Methods.tunnelStatus.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeTunnelStatusInterceptors() ?? [],
|
||||||
|
handler: handler
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(*, deprecated)
|
||||||
|
extension Burrow_TunnelClient: @unchecked Sendable {}
|
||||||
|
|
||||||
|
@available(*, deprecated, renamed: "Burrow_TunnelNIOClient")
|
||||||
|
public final class Burrow_TunnelClient: Burrow_TunnelClientProtocol {
|
||||||
|
private let lock = Lock()
|
||||||
|
private var _defaultCallOptions: CallOptions
|
||||||
|
private var _interceptors: Burrow_TunnelClientInterceptorFactoryProtocol?
|
||||||
|
public let channel: GRPCChannel
|
||||||
|
public var defaultCallOptions: CallOptions {
|
||||||
|
get { self.lock.withLock { return self._defaultCallOptions } }
|
||||||
|
set { self.lock.withLockVoid { self._defaultCallOptions = newValue } }
|
||||||
|
}
|
||||||
|
public var interceptors: Burrow_TunnelClientInterceptorFactoryProtocol? {
|
||||||
|
get { self.lock.withLock { return self._interceptors } }
|
||||||
|
set { self.lock.withLockVoid { self._interceptors = newValue } }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a client for the burrow.Tunnel service.
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - channel: `GRPCChannel` to the service host.
|
||||||
|
/// - defaultCallOptions: Options to use for each service call if the user doesn't provide them.
|
||||||
|
/// - interceptors: A factory providing interceptors for each RPC.
|
||||||
|
public init(
|
||||||
|
channel: GRPCChannel,
|
||||||
|
defaultCallOptions: CallOptions = CallOptions(),
|
||||||
|
interceptors: Burrow_TunnelClientInterceptorFactoryProtocol? = nil
|
||||||
|
) {
|
||||||
|
self.channel = channel
|
||||||
|
self._defaultCallOptions = defaultCallOptions
|
||||||
|
self._interceptors = interceptors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Burrow_TunnelNIOClient: Burrow_TunnelClientProtocol {
|
||||||
|
public var channel: GRPCChannel
|
||||||
|
public var defaultCallOptions: CallOptions
|
||||||
|
public var interceptors: Burrow_TunnelClientInterceptorFactoryProtocol?
|
||||||
|
|
||||||
|
/// Creates a client for the burrow.Tunnel service.
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - channel: `GRPCChannel` to the service host.
|
||||||
|
/// - defaultCallOptions: Options to use for each service call if the user doesn't provide them.
|
||||||
|
/// - interceptors: A factory providing interceptors for each RPC.
|
||||||
|
public init(
|
||||||
|
channel: GRPCChannel,
|
||||||
|
defaultCallOptions: CallOptions = CallOptions(),
|
||||||
|
interceptors: Burrow_TunnelClientInterceptorFactoryProtocol? = nil
|
||||||
|
) {
|
||||||
|
self.channel = channel
|
||||||
|
self.defaultCallOptions = defaultCallOptions
|
||||||
|
self.interceptors = interceptors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||||
|
public protocol Burrow_TunnelAsyncClientProtocol: GRPCClient {
|
||||||
|
static var serviceDescriptor: GRPCServiceDescriptor { get }
|
||||||
|
var interceptors: Burrow_TunnelClientInterceptorFactoryProtocol? { get }
|
||||||
|
|
||||||
|
func makeTunnelConfigurationCall(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> GRPCAsyncServerStreamingCall<Burrow_Empty, Burrow_TunnelConfigurationResponse>
|
||||||
|
|
||||||
|
func makeTunnelStartCall(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> GRPCAsyncUnaryCall<Burrow_Empty, Burrow_Empty>
|
||||||
|
|
||||||
|
func makeTunnelStopCall(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> GRPCAsyncUnaryCall<Burrow_Empty, Burrow_Empty>
|
||||||
|
|
||||||
|
func makeTunnelStatusCall(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> GRPCAsyncServerStreamingCall<Burrow_Empty, Burrow_TunnelStatusResponse>
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||||
|
extension Burrow_TunnelAsyncClientProtocol {
|
||||||
|
public static var serviceDescriptor: GRPCServiceDescriptor {
|
||||||
|
return Burrow_TunnelClientMetadata.serviceDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
public var interceptors: Burrow_TunnelClientInterceptorFactoryProtocol? {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeTunnelConfigurationCall(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> GRPCAsyncServerStreamingCall<Burrow_Empty, Burrow_TunnelConfigurationResponse> {
|
||||||
|
return self.makeAsyncServerStreamingCall(
|
||||||
|
path: Burrow_TunnelClientMetadata.Methods.tunnelConfiguration.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeTunnelConfigurationInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeTunnelStartCall(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> GRPCAsyncUnaryCall<Burrow_Empty, Burrow_Empty> {
|
||||||
|
return self.makeAsyncUnaryCall(
|
||||||
|
path: Burrow_TunnelClientMetadata.Methods.tunnelStart.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeTunnelStartInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeTunnelStopCall(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> GRPCAsyncUnaryCall<Burrow_Empty, Burrow_Empty> {
|
||||||
|
return self.makeAsyncUnaryCall(
|
||||||
|
path: Burrow_TunnelClientMetadata.Methods.tunnelStop.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeTunnelStopInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeTunnelStatusCall(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> GRPCAsyncServerStreamingCall<Burrow_Empty, Burrow_TunnelStatusResponse> {
|
||||||
|
return self.makeAsyncServerStreamingCall(
|
||||||
|
path: Burrow_TunnelClientMetadata.Methods.tunnelStatus.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeTunnelStatusInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||||
|
extension Burrow_TunnelAsyncClientProtocol {
|
||||||
|
public func tunnelConfiguration(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> GRPCAsyncResponseStream<Burrow_TunnelConfigurationResponse> {
|
||||||
|
return self.performAsyncServerStreamingCall(
|
||||||
|
path: Burrow_TunnelClientMetadata.Methods.tunnelConfiguration.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeTunnelConfigurationInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func tunnelStart(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) async throws -> Burrow_Empty {
|
||||||
|
return try await self.performAsyncUnaryCall(
|
||||||
|
path: Burrow_TunnelClientMetadata.Methods.tunnelStart.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeTunnelStartInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func tunnelStop(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) async throws -> Burrow_Empty {
|
||||||
|
return try await self.performAsyncUnaryCall(
|
||||||
|
path: Burrow_TunnelClientMetadata.Methods.tunnelStop.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeTunnelStopInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func tunnelStatus(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> GRPCAsyncResponseStream<Burrow_TunnelStatusResponse> {
|
||||||
|
return self.performAsyncServerStreamingCall(
|
||||||
|
path: Burrow_TunnelClientMetadata.Methods.tunnelStatus.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeTunnelStatusInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||||
|
public struct Burrow_TunnelAsyncClient: Burrow_TunnelAsyncClientProtocol {
|
||||||
|
public var channel: GRPCChannel
|
||||||
|
public var defaultCallOptions: CallOptions
|
||||||
|
public var interceptors: Burrow_TunnelClientInterceptorFactoryProtocol?
|
||||||
|
|
||||||
|
public init(
|
||||||
|
channel: GRPCChannel,
|
||||||
|
defaultCallOptions: CallOptions = CallOptions(),
|
||||||
|
interceptors: Burrow_TunnelClientInterceptorFactoryProtocol? = nil
|
||||||
|
) {
|
||||||
|
self.channel = channel
|
||||||
|
self.defaultCallOptions = defaultCallOptions
|
||||||
|
self.interceptors = interceptors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public protocol Burrow_TunnelClientInterceptorFactoryProtocol: Sendable {
|
||||||
|
|
||||||
|
/// - Returns: Interceptors to use when invoking 'tunnelConfiguration'.
|
||||||
|
func makeTunnelConfigurationInterceptors() -> [ClientInterceptor<Burrow_Empty, Burrow_TunnelConfigurationResponse>]
|
||||||
|
|
||||||
|
/// - Returns: Interceptors to use when invoking 'tunnelStart'.
|
||||||
|
func makeTunnelStartInterceptors() -> [ClientInterceptor<Burrow_Empty, Burrow_Empty>]
|
||||||
|
|
||||||
|
/// - Returns: Interceptors to use when invoking 'tunnelStop'.
|
||||||
|
func makeTunnelStopInterceptors() -> [ClientInterceptor<Burrow_Empty, Burrow_Empty>]
|
||||||
|
|
||||||
|
/// - Returns: Interceptors to use when invoking 'tunnelStatus'.
|
||||||
|
func makeTunnelStatusInterceptors() -> [ClientInterceptor<Burrow_Empty, Burrow_TunnelStatusResponse>]
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Burrow_TunnelClientMetadata {
|
||||||
|
public static let serviceDescriptor = GRPCServiceDescriptor(
|
||||||
|
name: "Tunnel",
|
||||||
|
fullName: "burrow.Tunnel",
|
||||||
|
methods: [
|
||||||
|
Burrow_TunnelClientMetadata.Methods.tunnelConfiguration,
|
||||||
|
Burrow_TunnelClientMetadata.Methods.tunnelStart,
|
||||||
|
Burrow_TunnelClientMetadata.Methods.tunnelStop,
|
||||||
|
Burrow_TunnelClientMetadata.Methods.tunnelStatus,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
public enum Methods {
|
||||||
|
public static let tunnelConfiguration = GRPCMethodDescriptor(
|
||||||
|
name: "TunnelConfiguration",
|
||||||
|
path: "/burrow.Tunnel/TunnelConfiguration",
|
||||||
|
type: GRPCCallType.serverStreaming
|
||||||
|
)
|
||||||
|
|
||||||
|
public static let tunnelStart = GRPCMethodDescriptor(
|
||||||
|
name: "TunnelStart",
|
||||||
|
path: "/burrow.Tunnel/TunnelStart",
|
||||||
|
type: GRPCCallType.unary
|
||||||
|
)
|
||||||
|
|
||||||
|
public static let tunnelStop = GRPCMethodDescriptor(
|
||||||
|
name: "TunnelStop",
|
||||||
|
path: "/burrow.Tunnel/TunnelStop",
|
||||||
|
type: GRPCCallType.unary
|
||||||
|
)
|
||||||
|
|
||||||
|
public static let tunnelStatus = GRPCMethodDescriptor(
|
||||||
|
name: "TunnelStatus",
|
||||||
|
path: "/burrow.Tunnel/TunnelStatus",
|
||||||
|
type: GRPCCallType.serverStreaming
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Usage: instantiate `Burrow_NetworksClient`, then call methods of this protocol to make API calls.
|
||||||
|
public protocol Burrow_NetworksClientProtocol: GRPCClient {
|
||||||
|
var serviceName: String { get }
|
||||||
|
var interceptors: Burrow_NetworksClientInterceptorFactoryProtocol? { get }
|
||||||
|
|
||||||
|
func networkAdd(
|
||||||
|
_ request: Burrow_Network,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> UnaryCall<Burrow_Network, Burrow_Empty>
|
||||||
|
|
||||||
|
func networkList(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions?,
|
||||||
|
handler: @escaping (Burrow_NetworkListResponse) -> Void
|
||||||
|
) -> ServerStreamingCall<Burrow_Empty, Burrow_NetworkListResponse>
|
||||||
|
|
||||||
|
func networkReorder(
|
||||||
|
_ request: Burrow_NetworkReorderRequest,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> UnaryCall<Burrow_NetworkReorderRequest, Burrow_Empty>
|
||||||
|
|
||||||
|
func networkDelete(
|
||||||
|
_ request: Burrow_NetworkDeleteRequest,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> UnaryCall<Burrow_NetworkDeleteRequest, Burrow_Empty>
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Burrow_NetworksClientProtocol {
|
||||||
|
public var serviceName: String {
|
||||||
|
return "burrow.Networks"
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unary call to NetworkAdd
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - request: Request to send to NetworkAdd.
|
||||||
|
/// - callOptions: Call options.
|
||||||
|
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||||
|
public func networkAdd(
|
||||||
|
_ request: Burrow_Network,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> UnaryCall<Burrow_Network, Burrow_Empty> {
|
||||||
|
return self.makeUnaryCall(
|
||||||
|
path: Burrow_NetworksClientMetadata.Methods.networkAdd.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeNetworkAddInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server streaming call to NetworkList
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - request: Request to send to NetworkList.
|
||||||
|
/// - callOptions: Call options.
|
||||||
|
/// - handler: A closure called when each response is received from the server.
|
||||||
|
/// - Returns: A `ServerStreamingCall` with futures for the metadata and status.
|
||||||
|
public func networkList(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil,
|
||||||
|
handler: @escaping (Burrow_NetworkListResponse) -> Void
|
||||||
|
) -> ServerStreamingCall<Burrow_Empty, Burrow_NetworkListResponse> {
|
||||||
|
return self.makeServerStreamingCall(
|
||||||
|
path: Burrow_NetworksClientMetadata.Methods.networkList.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeNetworkListInterceptors() ?? [],
|
||||||
|
handler: handler
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unary call to NetworkReorder
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - request: Request to send to NetworkReorder.
|
||||||
|
/// - callOptions: Call options.
|
||||||
|
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||||
|
public func networkReorder(
|
||||||
|
_ request: Burrow_NetworkReorderRequest,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> UnaryCall<Burrow_NetworkReorderRequest, Burrow_Empty> {
|
||||||
|
return self.makeUnaryCall(
|
||||||
|
path: Burrow_NetworksClientMetadata.Methods.networkReorder.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeNetworkReorderInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unary call to NetworkDelete
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - request: Request to send to NetworkDelete.
|
||||||
|
/// - callOptions: Call options.
|
||||||
|
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||||
|
public func networkDelete(
|
||||||
|
_ request: Burrow_NetworkDeleteRequest,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> UnaryCall<Burrow_NetworkDeleteRequest, Burrow_Empty> {
|
||||||
|
return self.makeUnaryCall(
|
||||||
|
path: Burrow_NetworksClientMetadata.Methods.networkDelete.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeNetworkDeleteInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(*, deprecated)
|
||||||
|
extension Burrow_NetworksClient: @unchecked Sendable {}
|
||||||
|
|
||||||
|
@available(*, deprecated, renamed: "Burrow_NetworksNIOClient")
|
||||||
|
public final class Burrow_NetworksClient: Burrow_NetworksClientProtocol {
|
||||||
|
private let lock = Lock()
|
||||||
|
private var _defaultCallOptions: CallOptions
|
||||||
|
private var _interceptors: Burrow_NetworksClientInterceptorFactoryProtocol?
|
||||||
|
public let channel: GRPCChannel
|
||||||
|
public var defaultCallOptions: CallOptions {
|
||||||
|
get { self.lock.withLock { return self._defaultCallOptions } }
|
||||||
|
set { self.lock.withLockVoid { self._defaultCallOptions = newValue } }
|
||||||
|
}
|
||||||
|
public var interceptors: Burrow_NetworksClientInterceptorFactoryProtocol? {
|
||||||
|
get { self.lock.withLock { return self._interceptors } }
|
||||||
|
set { self.lock.withLockVoid { self._interceptors = newValue } }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a client for the burrow.Networks service.
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - channel: `GRPCChannel` to the service host.
|
||||||
|
/// - defaultCallOptions: Options to use for each service call if the user doesn't provide them.
|
||||||
|
/// - interceptors: A factory providing interceptors for each RPC.
|
||||||
|
public init(
|
||||||
|
channel: GRPCChannel,
|
||||||
|
defaultCallOptions: CallOptions = CallOptions(),
|
||||||
|
interceptors: Burrow_NetworksClientInterceptorFactoryProtocol? = nil
|
||||||
|
) {
|
||||||
|
self.channel = channel
|
||||||
|
self._defaultCallOptions = defaultCallOptions
|
||||||
|
self._interceptors = interceptors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Burrow_NetworksNIOClient: Burrow_NetworksClientProtocol {
|
||||||
|
public var channel: GRPCChannel
|
||||||
|
public var defaultCallOptions: CallOptions
|
||||||
|
public var interceptors: Burrow_NetworksClientInterceptorFactoryProtocol?
|
||||||
|
|
||||||
|
/// Creates a client for the burrow.Networks service.
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - channel: `GRPCChannel` to the service host.
|
||||||
|
/// - defaultCallOptions: Options to use for each service call if the user doesn't provide them.
|
||||||
|
/// - interceptors: A factory providing interceptors for each RPC.
|
||||||
|
public init(
|
||||||
|
channel: GRPCChannel,
|
||||||
|
defaultCallOptions: CallOptions = CallOptions(),
|
||||||
|
interceptors: Burrow_NetworksClientInterceptorFactoryProtocol? = nil
|
||||||
|
) {
|
||||||
|
self.channel = channel
|
||||||
|
self.defaultCallOptions = defaultCallOptions
|
||||||
|
self.interceptors = interceptors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||||
|
public protocol Burrow_NetworksAsyncClientProtocol: GRPCClient {
|
||||||
|
static var serviceDescriptor: GRPCServiceDescriptor { get }
|
||||||
|
var interceptors: Burrow_NetworksClientInterceptorFactoryProtocol? { get }
|
||||||
|
|
||||||
|
func makeNetworkAddCall(
|
||||||
|
_ request: Burrow_Network,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> GRPCAsyncUnaryCall<Burrow_Network, Burrow_Empty>
|
||||||
|
|
||||||
|
func makeNetworkListCall(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> GRPCAsyncServerStreamingCall<Burrow_Empty, Burrow_NetworkListResponse>
|
||||||
|
|
||||||
|
func makeNetworkReorderCall(
|
||||||
|
_ request: Burrow_NetworkReorderRequest,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> GRPCAsyncUnaryCall<Burrow_NetworkReorderRequest, Burrow_Empty>
|
||||||
|
|
||||||
|
func makeNetworkDeleteCall(
|
||||||
|
_ request: Burrow_NetworkDeleteRequest,
|
||||||
|
callOptions: CallOptions?
|
||||||
|
) -> GRPCAsyncUnaryCall<Burrow_NetworkDeleteRequest, Burrow_Empty>
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||||
|
extension Burrow_NetworksAsyncClientProtocol {
|
||||||
|
public static var serviceDescriptor: GRPCServiceDescriptor {
|
||||||
|
return Burrow_NetworksClientMetadata.serviceDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
public var interceptors: Burrow_NetworksClientInterceptorFactoryProtocol? {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeNetworkAddCall(
|
||||||
|
_ request: Burrow_Network,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> GRPCAsyncUnaryCall<Burrow_Network, Burrow_Empty> {
|
||||||
|
return self.makeAsyncUnaryCall(
|
||||||
|
path: Burrow_NetworksClientMetadata.Methods.networkAdd.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeNetworkAddInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeNetworkListCall(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> GRPCAsyncServerStreamingCall<Burrow_Empty, Burrow_NetworkListResponse> {
|
||||||
|
return self.makeAsyncServerStreamingCall(
|
||||||
|
path: Burrow_NetworksClientMetadata.Methods.networkList.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeNetworkListInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeNetworkReorderCall(
|
||||||
|
_ request: Burrow_NetworkReorderRequest,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> GRPCAsyncUnaryCall<Burrow_NetworkReorderRequest, Burrow_Empty> {
|
||||||
|
return self.makeAsyncUnaryCall(
|
||||||
|
path: Burrow_NetworksClientMetadata.Methods.networkReorder.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeNetworkReorderInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeNetworkDeleteCall(
|
||||||
|
_ request: Burrow_NetworkDeleteRequest,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> GRPCAsyncUnaryCall<Burrow_NetworkDeleteRequest, Burrow_Empty> {
|
||||||
|
return self.makeAsyncUnaryCall(
|
||||||
|
path: Burrow_NetworksClientMetadata.Methods.networkDelete.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeNetworkDeleteInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||||
|
extension Burrow_NetworksAsyncClientProtocol {
|
||||||
|
public func networkAdd(
|
||||||
|
_ request: Burrow_Network,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) async throws -> Burrow_Empty {
|
||||||
|
return try await self.performAsyncUnaryCall(
|
||||||
|
path: Burrow_NetworksClientMetadata.Methods.networkAdd.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeNetworkAddInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func networkList(
|
||||||
|
_ request: Burrow_Empty,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) -> GRPCAsyncResponseStream<Burrow_NetworkListResponse> {
|
||||||
|
return self.performAsyncServerStreamingCall(
|
||||||
|
path: Burrow_NetworksClientMetadata.Methods.networkList.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeNetworkListInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func networkReorder(
|
||||||
|
_ request: Burrow_NetworkReorderRequest,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) async throws -> Burrow_Empty {
|
||||||
|
return try await self.performAsyncUnaryCall(
|
||||||
|
path: Burrow_NetworksClientMetadata.Methods.networkReorder.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeNetworkReorderInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func networkDelete(
|
||||||
|
_ request: Burrow_NetworkDeleteRequest,
|
||||||
|
callOptions: CallOptions? = nil
|
||||||
|
) async throws -> Burrow_Empty {
|
||||||
|
return try await self.performAsyncUnaryCall(
|
||||||
|
path: Burrow_NetworksClientMetadata.Methods.networkDelete.path,
|
||||||
|
request: request,
|
||||||
|
callOptions: callOptions ?? self.defaultCallOptions,
|
||||||
|
interceptors: self.interceptors?.makeNetworkDeleteInterceptors() ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||||
|
public struct Burrow_NetworksAsyncClient: Burrow_NetworksAsyncClientProtocol {
|
||||||
|
public var channel: GRPCChannel
|
||||||
|
public var defaultCallOptions: CallOptions
|
||||||
|
public var interceptors: Burrow_NetworksClientInterceptorFactoryProtocol?
|
||||||
|
|
||||||
|
public init(
|
||||||
|
channel: GRPCChannel,
|
||||||
|
defaultCallOptions: CallOptions = CallOptions(),
|
||||||
|
interceptors: Burrow_NetworksClientInterceptorFactoryProtocol? = nil
|
||||||
|
) {
|
||||||
|
self.channel = channel
|
||||||
|
self.defaultCallOptions = defaultCallOptions
|
||||||
|
self.interceptors = interceptors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public protocol Burrow_NetworksClientInterceptorFactoryProtocol: Sendable {
|
||||||
|
|
||||||
|
/// - Returns: Interceptors to use when invoking 'networkAdd'.
|
||||||
|
func makeNetworkAddInterceptors() -> [ClientInterceptor<Burrow_Network, Burrow_Empty>]
|
||||||
|
|
||||||
|
/// - Returns: Interceptors to use when invoking 'networkList'.
|
||||||
|
func makeNetworkListInterceptors() -> [ClientInterceptor<Burrow_Empty, Burrow_NetworkListResponse>]
|
||||||
|
|
||||||
|
/// - Returns: Interceptors to use when invoking 'networkReorder'.
|
||||||
|
func makeNetworkReorderInterceptors() -> [ClientInterceptor<Burrow_NetworkReorderRequest, Burrow_Empty>]
|
||||||
|
|
||||||
|
/// - Returns: Interceptors to use when invoking 'networkDelete'.
|
||||||
|
func makeNetworkDeleteInterceptors() -> [ClientInterceptor<Burrow_NetworkDeleteRequest, Burrow_Empty>]
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Burrow_NetworksClientMetadata {
|
||||||
|
public static let serviceDescriptor = GRPCServiceDescriptor(
|
||||||
|
name: "Networks",
|
||||||
|
fullName: "burrow.Networks",
|
||||||
|
methods: [
|
||||||
|
Burrow_NetworksClientMetadata.Methods.networkAdd,
|
||||||
|
Burrow_NetworksClientMetadata.Methods.networkList,
|
||||||
|
Burrow_NetworksClientMetadata.Methods.networkReorder,
|
||||||
|
Burrow_NetworksClientMetadata.Methods.networkDelete,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
public enum Methods {
|
||||||
|
public static let networkAdd = GRPCMethodDescriptor(
|
||||||
|
name: "NetworkAdd",
|
||||||
|
path: "/burrow.Networks/NetworkAdd",
|
||||||
|
type: GRPCCallType.unary
|
||||||
|
)
|
||||||
|
|
||||||
|
public static let networkList = GRPCMethodDescriptor(
|
||||||
|
name: "NetworkList",
|
||||||
|
path: "/burrow.Networks/NetworkList",
|
||||||
|
type: GRPCCallType.serverStreaming
|
||||||
|
)
|
||||||
|
|
||||||
|
public static let networkReorder = GRPCMethodDescriptor(
|
||||||
|
name: "NetworkReorder",
|
||||||
|
path: "/burrow.Networks/NetworkReorder",
|
||||||
|
type: GRPCCallType.unary
|
||||||
|
)
|
||||||
|
|
||||||
|
public static let networkDelete = GRPCMethodDescriptor(
|
||||||
|
name: "NetworkDelete",
|
||||||
|
path: "/burrow.Networks/NetworkDelete",
|
||||||
|
type: GRPCCallType.unary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
566
Apple/Core/Client/Generated/burrow.pb.swift
Normal file
566
Apple/Core/Client/Generated/burrow.pb.swift
Normal file
|
|
@ -0,0 +1,566 @@
|
||||||
|
// DO NOT EDIT.
|
||||||
|
// swift-format-ignore-file
|
||||||
|
// swiftlint:disable all
|
||||||
|
//
|
||||||
|
// Generated by the Swift generator plugin for the protocol buffer compiler.
|
||||||
|
// Source: burrow.proto
|
||||||
|
//
|
||||||
|
// For information on using the generated types, please see the documentation:
|
||||||
|
// https://github.com/apple/swift-protobuf/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SwiftProtobuf
|
||||||
|
|
||||||
|
// If the compiler emits an error on this type, it is because this file
|
||||||
|
// was generated by a version of the `protoc` Swift plug-in that is
|
||||||
|
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||||
|
// Please ensure that you are building against the same version of the API
|
||||||
|
// that was used to generate this file.
|
||||||
|
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||||
|
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||||
|
typealias Version = _2
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Burrow_NetworkType: SwiftProtobuf.Enum, Swift.CaseIterable {
|
||||||
|
public typealias RawValue = Int
|
||||||
|
case wireGuard // = 0
|
||||||
|
case tailnet // = 1
|
||||||
|
case UNRECOGNIZED(Int)
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
self = .wireGuard
|
||||||
|
}
|
||||||
|
|
||||||
|
public init?(rawValue: Int) {
|
||||||
|
switch rawValue {
|
||||||
|
case 0: self = .wireGuard
|
||||||
|
case 1: self = .tailnet
|
||||||
|
default: self = .UNRECOGNIZED(rawValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var rawValue: Int {
|
||||||
|
switch self {
|
||||||
|
case .wireGuard: return 0
|
||||||
|
case .tailnet: return 1
|
||||||
|
case .UNRECOGNIZED(let i): return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The compiler won't synthesize support with the UNRECOGNIZED case.
|
||||||
|
public static let allCases: [Burrow_NetworkType] = [
|
||||||
|
.wireGuard,
|
||||||
|
.tailnet,
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Burrow_State: SwiftProtobuf.Enum, Swift.CaseIterable {
|
||||||
|
public typealias RawValue = Int
|
||||||
|
case stopped // = 0
|
||||||
|
case running // = 1
|
||||||
|
case UNRECOGNIZED(Int)
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
self = .stopped
|
||||||
|
}
|
||||||
|
|
||||||
|
public init?(rawValue: Int) {
|
||||||
|
switch rawValue {
|
||||||
|
case 0: self = .stopped
|
||||||
|
case 1: self = .running
|
||||||
|
default: self = .UNRECOGNIZED(rawValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var rawValue: Int {
|
||||||
|
switch self {
|
||||||
|
case .stopped: return 0
|
||||||
|
case .running: return 1
|
||||||
|
case .UNRECOGNIZED(let i): return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The compiler won't synthesize support with the UNRECOGNIZED case.
|
||||||
|
public static let allCases: [Burrow_State] = [
|
||||||
|
.stopped,
|
||||||
|
.running,
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Burrow_NetworkReorderRequest: Sendable {
|
||||||
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
// methods supported on all messages.
|
||||||
|
|
||||||
|
public var id: Int32 = 0
|
||||||
|
|
||||||
|
public var index: Int32 = 0
|
||||||
|
|
||||||
|
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Burrow_WireGuardPeer: Sendable {
|
||||||
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
// methods supported on all messages.
|
||||||
|
|
||||||
|
public var endpoint: String = String()
|
||||||
|
|
||||||
|
public var subnet: [String] = []
|
||||||
|
|
||||||
|
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Burrow_WireGuardNetwork: Sendable {
|
||||||
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
// methods supported on all messages.
|
||||||
|
|
||||||
|
public var address: String = String()
|
||||||
|
|
||||||
|
public var dns: String = String()
|
||||||
|
|
||||||
|
public var peer: [Burrow_WireGuardPeer] = []
|
||||||
|
|
||||||
|
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Burrow_NetworkDeleteRequest: Sendable {
|
||||||
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
// methods supported on all messages.
|
||||||
|
|
||||||
|
public var id: Int32 = 0
|
||||||
|
|
||||||
|
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Burrow_Network: @unchecked Sendable {
|
||||||
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
// methods supported on all messages.
|
||||||
|
|
||||||
|
public var id: Int32 = 0
|
||||||
|
|
||||||
|
public var type: Burrow_NetworkType = .wireGuard
|
||||||
|
|
||||||
|
public var payload: Data = Data()
|
||||||
|
|
||||||
|
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Burrow_NetworkListResponse: Sendable {
|
||||||
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
// methods supported on all messages.
|
||||||
|
|
||||||
|
public var network: [Burrow_Network] = []
|
||||||
|
|
||||||
|
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Burrow_Empty: Sendable {
|
||||||
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
// methods supported on all messages.
|
||||||
|
|
||||||
|
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Burrow_TunnelStatusResponse: Sendable {
|
||||||
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
// methods supported on all messages.
|
||||||
|
|
||||||
|
public var state: Burrow_State = .stopped
|
||||||
|
|
||||||
|
public var start: SwiftProtobuf.Google_Protobuf_Timestamp {
|
||||||
|
get {return _start ?? SwiftProtobuf.Google_Protobuf_Timestamp()}
|
||||||
|
set {_start = newValue}
|
||||||
|
}
|
||||||
|
/// Returns true if `start` has been explicitly set.
|
||||||
|
public var hasStart: Bool {return self._start != nil}
|
||||||
|
/// Clears the value of `start`. Subsequent reads from it will return its default value.
|
||||||
|
public mutating func clearStart() {self._start = nil}
|
||||||
|
|
||||||
|
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
|
||||||
|
fileprivate var _start: SwiftProtobuf.Google_Protobuf_Timestamp? = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Burrow_TunnelConfigurationResponse: Sendable {
|
||||||
|
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||||
|
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||||
|
// methods supported on all messages.
|
||||||
|
|
||||||
|
public var addresses: [String] = []
|
||||||
|
|
||||||
|
public var mtu: Int32 = 0
|
||||||
|
|
||||||
|
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||||
|
|
||||||
|
fileprivate let _protobuf_package = "burrow"
|
||||||
|
|
||||||
|
extension Burrow_NetworkType: SwiftProtobuf._ProtoNameProviding {
|
||||||
|
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||||
|
0: .same(proto: "WireGuard"),
|
||||||
|
1: .same(proto: "Tailnet"),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Burrow_State: SwiftProtobuf._ProtoNameProviding {
|
||||||
|
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||||
|
0: .same(proto: "Stopped"),
|
||||||
|
1: .same(proto: "Running"),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Burrow_NetworkReorderRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||||
|
public static let protoMessageName: String = _protobuf_package + ".NetworkReorderRequest"
|
||||||
|
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||||
|
1: .same(proto: "id"),
|
||||||
|
2: .same(proto: "index"),
|
||||||
|
]
|
||||||
|
|
||||||
|
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||||
|
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||||
|
// The use of inline closures is to circumvent an issue where the compiler
|
||||||
|
// allocates stack space for every case branch when no optimizations are
|
||||||
|
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||||
|
switch fieldNumber {
|
||||||
|
case 1: try { try decoder.decodeSingularInt32Field(value: &self.id) }()
|
||||||
|
case 2: try { try decoder.decodeSingularInt32Field(value: &self.index) }()
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||||
|
if self.id != 0 {
|
||||||
|
try visitor.visitSingularInt32Field(value: self.id, fieldNumber: 1)
|
||||||
|
}
|
||||||
|
if self.index != 0 {
|
||||||
|
try visitor.visitSingularInt32Field(value: self.index, fieldNumber: 2)
|
||||||
|
}
|
||||||
|
try unknownFields.traverse(visitor: &visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Burrow_NetworkReorderRequest, rhs: Burrow_NetworkReorderRequest) -> Bool {
|
||||||
|
if lhs.id != rhs.id {return false}
|
||||||
|
if lhs.index != rhs.index {return false}
|
||||||
|
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Burrow_WireGuardPeer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||||
|
public static let protoMessageName: String = _protobuf_package + ".WireGuardPeer"
|
||||||
|
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||||
|
1: .same(proto: "endpoint"),
|
||||||
|
2: .same(proto: "subnet"),
|
||||||
|
]
|
||||||
|
|
||||||
|
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||||
|
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||||
|
// The use of inline closures is to circumvent an issue where the compiler
|
||||||
|
// allocates stack space for every case branch when no optimizations are
|
||||||
|
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||||
|
switch fieldNumber {
|
||||||
|
case 1: try { try decoder.decodeSingularStringField(value: &self.endpoint) }()
|
||||||
|
case 2: try { try decoder.decodeRepeatedStringField(value: &self.subnet) }()
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||||
|
if !self.endpoint.isEmpty {
|
||||||
|
try visitor.visitSingularStringField(value: self.endpoint, fieldNumber: 1)
|
||||||
|
}
|
||||||
|
if !self.subnet.isEmpty {
|
||||||
|
try visitor.visitRepeatedStringField(value: self.subnet, fieldNumber: 2)
|
||||||
|
}
|
||||||
|
try unknownFields.traverse(visitor: &visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Burrow_WireGuardPeer, rhs: Burrow_WireGuardPeer) -> Bool {
|
||||||
|
if lhs.endpoint != rhs.endpoint {return false}
|
||||||
|
if lhs.subnet != rhs.subnet {return false}
|
||||||
|
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Burrow_WireGuardNetwork: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||||
|
public static let protoMessageName: String = _protobuf_package + ".WireGuardNetwork"
|
||||||
|
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||||
|
1: .same(proto: "address"),
|
||||||
|
2: .same(proto: "dns"),
|
||||||
|
3: .same(proto: "peer"),
|
||||||
|
]
|
||||||
|
|
||||||
|
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||||
|
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||||
|
// The use of inline closures is to circumvent an issue where the compiler
|
||||||
|
// allocates stack space for every case branch when no optimizations are
|
||||||
|
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||||
|
switch fieldNumber {
|
||||||
|
case 1: try { try decoder.decodeSingularStringField(value: &self.address) }()
|
||||||
|
case 2: try { try decoder.decodeSingularStringField(value: &self.dns) }()
|
||||||
|
case 3: try { try decoder.decodeRepeatedMessageField(value: &self.peer) }()
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||||
|
if !self.address.isEmpty {
|
||||||
|
try visitor.visitSingularStringField(value: self.address, fieldNumber: 1)
|
||||||
|
}
|
||||||
|
if !self.dns.isEmpty {
|
||||||
|
try visitor.visitSingularStringField(value: self.dns, fieldNumber: 2)
|
||||||
|
}
|
||||||
|
if !self.peer.isEmpty {
|
||||||
|
try visitor.visitRepeatedMessageField(value: self.peer, fieldNumber: 3)
|
||||||
|
}
|
||||||
|
try unknownFields.traverse(visitor: &visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Burrow_WireGuardNetwork, rhs: Burrow_WireGuardNetwork) -> Bool {
|
||||||
|
if lhs.address != rhs.address {return false}
|
||||||
|
if lhs.dns != rhs.dns {return false}
|
||||||
|
if lhs.peer != rhs.peer {return false}
|
||||||
|
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Burrow_NetworkDeleteRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||||
|
public static let protoMessageName: String = _protobuf_package + ".NetworkDeleteRequest"
|
||||||
|
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||||
|
1: .same(proto: "id"),
|
||||||
|
]
|
||||||
|
|
||||||
|
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||||
|
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||||
|
// The use of inline closures is to circumvent an issue where the compiler
|
||||||
|
// allocates stack space for every case branch when no optimizations are
|
||||||
|
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||||
|
switch fieldNumber {
|
||||||
|
case 1: try { try decoder.decodeSingularInt32Field(value: &self.id) }()
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||||
|
if self.id != 0 {
|
||||||
|
try visitor.visitSingularInt32Field(value: self.id, fieldNumber: 1)
|
||||||
|
}
|
||||||
|
try unknownFields.traverse(visitor: &visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Burrow_NetworkDeleteRequest, rhs: Burrow_NetworkDeleteRequest) -> Bool {
|
||||||
|
if lhs.id != rhs.id {return false}
|
||||||
|
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Burrow_Network: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||||
|
public static let protoMessageName: String = _protobuf_package + ".Network"
|
||||||
|
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||||
|
1: .same(proto: "id"),
|
||||||
|
2: .same(proto: "type"),
|
||||||
|
3: .same(proto: "payload"),
|
||||||
|
]
|
||||||
|
|
||||||
|
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||||
|
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||||
|
// The use of inline closures is to circumvent an issue where the compiler
|
||||||
|
// allocates stack space for every case branch when no optimizations are
|
||||||
|
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||||
|
switch fieldNumber {
|
||||||
|
case 1: try { try decoder.decodeSingularInt32Field(value: &self.id) }()
|
||||||
|
case 2: try { try decoder.decodeSingularEnumField(value: &self.type) }()
|
||||||
|
case 3: try { try decoder.decodeSingularBytesField(value: &self.payload) }()
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||||
|
if self.id != 0 {
|
||||||
|
try visitor.visitSingularInt32Field(value: self.id, fieldNumber: 1)
|
||||||
|
}
|
||||||
|
if self.type != .wireGuard {
|
||||||
|
try visitor.visitSingularEnumField(value: self.type, fieldNumber: 2)
|
||||||
|
}
|
||||||
|
if !self.payload.isEmpty {
|
||||||
|
try visitor.visitSingularBytesField(value: self.payload, fieldNumber: 3)
|
||||||
|
}
|
||||||
|
try unknownFields.traverse(visitor: &visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Burrow_Network, rhs: Burrow_Network) -> Bool {
|
||||||
|
if lhs.id != rhs.id {return false}
|
||||||
|
if lhs.type != rhs.type {return false}
|
||||||
|
if lhs.payload != rhs.payload {return false}
|
||||||
|
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Burrow_NetworkListResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||||
|
public static let protoMessageName: String = _protobuf_package + ".NetworkListResponse"
|
||||||
|
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||||
|
1: .same(proto: "network"),
|
||||||
|
]
|
||||||
|
|
||||||
|
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||||
|
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||||
|
// The use of inline closures is to circumvent an issue where the compiler
|
||||||
|
// allocates stack space for every case branch when no optimizations are
|
||||||
|
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||||
|
switch fieldNumber {
|
||||||
|
case 1: try { try decoder.decodeRepeatedMessageField(value: &self.network) }()
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||||
|
if !self.network.isEmpty {
|
||||||
|
try visitor.visitRepeatedMessageField(value: self.network, fieldNumber: 1)
|
||||||
|
}
|
||||||
|
try unknownFields.traverse(visitor: &visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Burrow_NetworkListResponse, rhs: Burrow_NetworkListResponse) -> Bool {
|
||||||
|
if lhs.network != rhs.network {return false}
|
||||||
|
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Burrow_Empty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||||
|
public static let protoMessageName: String = _protobuf_package + ".Empty"
|
||||||
|
public static let _protobuf_nameMap = SwiftProtobuf._NameMap()
|
||||||
|
|
||||||
|
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||||
|
// Load everything into unknown fields
|
||||||
|
while try decoder.nextFieldNumber() != nil {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||||
|
try unknownFields.traverse(visitor: &visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Burrow_Empty, rhs: Burrow_Empty) -> Bool {
|
||||||
|
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Burrow_TunnelStatusResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||||
|
public static let protoMessageName: String = _protobuf_package + ".TunnelStatusResponse"
|
||||||
|
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||||
|
1: .same(proto: "state"),
|
||||||
|
2: .same(proto: "start"),
|
||||||
|
]
|
||||||
|
|
||||||
|
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||||
|
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||||
|
// The use of inline closures is to circumvent an issue where the compiler
|
||||||
|
// allocates stack space for every case branch when no optimizations are
|
||||||
|
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||||
|
switch fieldNumber {
|
||||||
|
case 1: try { try decoder.decodeSingularEnumField(value: &self.state) }()
|
||||||
|
case 2: try { try decoder.decodeSingularMessageField(value: &self._start) }()
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||||
|
// The use of inline closures is to circumvent an issue where the compiler
|
||||||
|
// allocates stack space for every if/case branch local when no optimizations
|
||||||
|
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||||
|
// https://github.com/apple/swift-protobuf/issues/1182
|
||||||
|
if self.state != .stopped {
|
||||||
|
try visitor.visitSingularEnumField(value: self.state, fieldNumber: 1)
|
||||||
|
}
|
||||||
|
try { if let v = self._start {
|
||||||
|
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||||
|
} }()
|
||||||
|
try unknownFields.traverse(visitor: &visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Burrow_TunnelStatusResponse, rhs: Burrow_TunnelStatusResponse) -> Bool {
|
||||||
|
if lhs.state != rhs.state {return false}
|
||||||
|
if lhs._start != rhs._start {return false}
|
||||||
|
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Burrow_TunnelConfigurationResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||||
|
public static let protoMessageName: String = _protobuf_package + ".TunnelConfigurationResponse"
|
||||||
|
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||||
|
1: .same(proto: "addresses"),
|
||||||
|
2: .same(proto: "mtu"),
|
||||||
|
]
|
||||||
|
|
||||||
|
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||||
|
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||||
|
// The use of inline closures is to circumvent an issue where the compiler
|
||||||
|
// allocates stack space for every case branch when no optimizations are
|
||||||
|
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||||
|
switch fieldNumber {
|
||||||
|
case 1: try { try decoder.decodeRepeatedStringField(value: &self.addresses) }()
|
||||||
|
case 2: try { try decoder.decodeSingularInt32Field(value: &self.mtu) }()
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||||
|
if !self.addresses.isEmpty {
|
||||||
|
try visitor.visitRepeatedStringField(value: self.addresses, fieldNumber: 1)
|
||||||
|
}
|
||||||
|
if self.mtu != 0 {
|
||||||
|
try visitor.visitSingularInt32Field(value: self.mtu, fieldNumber: 2)
|
||||||
|
}
|
||||||
|
try unknownFields.traverse(visitor: &visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Burrow_TunnelConfigurationResponse, rhs: Burrow_TunnelConfigurationResponse) -> Bool {
|
||||||
|
if lhs.addresses != rhs.addresses {return false}
|
||||||
|
if lhs.mtu != rhs.mtu {return false}
|
||||||
|
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"invocations": [
|
|
||||||
{
|
|
||||||
"protoFiles": [
|
|
||||||
"burrow.proto",
|
|
||||||
],
|
|
||||||
"server": false,
|
|
||||||
"visibility": "public"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"invocations": [
|
|
||||||
{
|
|
||||||
"protoFiles": [
|
|
||||||
"burrow.proto",
|
|
||||||
],
|
|
||||||
"visibility": "public"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -284,6 +284,7 @@ private struct AccountDraft {
|
||||||
var identityName = ""
|
var identityName = ""
|
||||||
var wireGuardConfig = ""
|
var wireGuardConfig = ""
|
||||||
|
|
||||||
|
var discoveryEmail = ""
|
||||||
var tailnetProvider: TailnetProvider = .tailscale
|
var tailnetProvider: TailnetProvider = .tailscale
|
||||||
var authority = ""
|
var authority = ""
|
||||||
var tailnet = ""
|
var tailnet = ""
|
||||||
|
|
@ -327,6 +328,9 @@ private struct ConfigurationSheetView: View {
|
||||||
@State private var errorMessage: String?
|
@State private var errorMessage: String?
|
||||||
@State private var loginSessionID: String?
|
@State private var loginSessionID: String?
|
||||||
@State private var loginStatus: TailnetLoginStatus?
|
@State private var loginStatus: TailnetLoginStatus?
|
||||||
|
@State private var discoveryStatus: TailnetDiscoveryResponse?
|
||||||
|
@State private var discoveryError: String?
|
||||||
|
@State private var isDiscoveringTailnet = false
|
||||||
@State private var authorityProbeStatus: TailnetAuthorityProbeStatus?
|
@State private var authorityProbeStatus: TailnetAuthorityProbeStatus?
|
||||||
@State private var authorityProbeError: String?
|
@State private var authorityProbeError: String?
|
||||||
@State private var isProbingAuthority = false
|
@State private var isProbingAuthority = false
|
||||||
|
|
@ -449,6 +453,9 @@ private struct ConfigurationSheetView: View {
|
||||||
.onChange(of: draft.authority) { _, _ in
|
.onChange(of: draft.authority) { _, _ in
|
||||||
resetAuthorityProbe()
|
resetAuthorityProbe()
|
||||||
}
|
}
|
||||||
|
.onChange(of: draft.discoveryEmail) { _, _ in
|
||||||
|
resetTailnetDiscoveryFeedback()
|
||||||
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
pollingTask?.cancel()
|
pollingTask?.cancel()
|
||||||
webAuthenticationTask?.cancel()
|
webAuthenticationTask?.cancel()
|
||||||
|
|
@ -459,7 +466,37 @@ private struct ConfigurationSheetView: View {
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var tailnetSections: some View {
|
private var tailnetSections: some View {
|
||||||
Section("Connection") {
|
Section("Connection") {
|
||||||
Picker("Provider", selection: $draft.tailnetProvider) {
|
TextField("Email address", text: $draft.discoveryEmail)
|
||||||
|
.textInputAutocapitalization(.never)
|
||||||
|
.keyboardType(.emailAddress)
|
||||||
|
.burrowLoginField()
|
||||||
|
.autocorrectionDisabled()
|
||||||
|
|
||||||
|
Button {
|
||||||
|
discoverTailnetAuthority()
|
||||||
|
} label: {
|
||||||
|
Label {
|
||||||
|
Text(isDiscoveringTailnet ? "Finding Server" : "Find Server")
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: isDiscoveringTailnet ? "hourglass" : "at.circle")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttonStyle(.borderless)
|
||||||
|
.disabled(isDiscoveringTailnet || normalizedOptional(draft.discoveryEmail) == nil)
|
||||||
|
|
||||||
|
if let discoveryStatus {
|
||||||
|
tailnetDiscoveryCard(status: discoveryStatus, failure: nil)
|
||||||
|
} else if let discoveryError {
|
||||||
|
tailnetDiscoveryCard(status: nil, failure: discoveryError)
|
||||||
|
}
|
||||||
|
|
||||||
|
Picker(
|
||||||
|
"Provider",
|
||||||
|
selection: Binding(
|
||||||
|
get: { draft.tailnetProvider },
|
||||||
|
set: { applyTailnetProvider($0) }
|
||||||
|
)
|
||||||
|
) {
|
||||||
ForEach(TailnetProvider.allCases) { provider in
|
ForEach(TailnetProvider.allCases) { provider in
|
||||||
Text(provider.title).tag(provider)
|
Text(provider.title).tag(provider)
|
||||||
}
|
}
|
||||||
|
|
@ -503,14 +540,14 @@ private struct ConfigurationSheetView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
Section("Authentication") {
|
Section("Authentication") {
|
||||||
if draft.tailnetProvider.usesWebLogin {
|
if tailnetUsesWebLogin {
|
||||||
tailnetWebLoginCard
|
tailnetWebLoginCard
|
||||||
} else {
|
} else {
|
||||||
TextField("Username", text: $draft.username)
|
TextField("Username", text: $draft.username)
|
||||||
.burrowLoginField()
|
.burrowLoginField()
|
||||||
.autocorrectionDisabled()
|
.autocorrectionDisabled()
|
||||||
Picker("Authentication", selection: $draft.authMode) {
|
Picker("Authentication", selection: $draft.authMode) {
|
||||||
ForEach([AccountAuthMode.none, .password, .preauthKey]) { mode in
|
ForEach(availableTailnetAuthModes) { mode in
|
||||||
Text(mode.title).tag(mode)
|
Text(mode.title).tag(mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -583,7 +620,7 @@ private struct ConfigurationSheetView: View {
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
summaryBadge(draft.tailnetProvider.title)
|
summaryBadge(draft.tailnetProvider.title)
|
||||||
summaryBadge(
|
summaryBadge(
|
||||||
draft.tailnetProvider.usesWebLogin ? "Web Sign-In" : draft.authMode.title
|
tailnetUsesWebLogin ? "Web Sign-In" : draft.authMode.title
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -656,7 +693,7 @@ private struct ConfigurationSheetView: View {
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Text("Burrow launches the local bridge, then opens the real Tailscale sign-in page in-app.")
|
Text("Burrow launches the local bridge, then opens the real provider sign-in page in-app.")
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
|
|
@ -696,6 +733,41 @@ private struct ConfigurationSheetView: View {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func tailnetDiscoveryCard(
|
||||||
|
status: TailnetDiscoveryResponse?,
|
||||||
|
failure: String?
|
||||||
|
) -> some View {
|
||||||
|
VStack(alignment: .leading, spacing: 6) {
|
||||||
|
if let status {
|
||||||
|
Text("Discovered \(status.provider.title)")
|
||||||
|
.font(.subheadline.weight(.medium))
|
||||||
|
Text(status.authority)
|
||||||
|
.font(.footnote.monospaced())
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
.textSelection(.enabled)
|
||||||
|
if let oidcIssuer = status.oidcIssuer {
|
||||||
|
Text("OIDC: \(oidcIssuer)")
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
.lineLimit(3)
|
||||||
|
.textSelection(.enabled)
|
||||||
|
}
|
||||||
|
} else if let failure {
|
||||||
|
Text("Discovery failed")
|
||||||
|
.font(.subheadline.weight(.medium))
|
||||||
|
.foregroundStyle(.red)
|
||||||
|
Text(failure)
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(12)
|
||||||
|
.background(
|
||||||
|
RoundedRectangle(cornerRadius: 16)
|
||||||
|
.fill(.thinMaterial)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private func summaryBadge(_ label: String) -> some View {
|
private func summaryBadge(_ label: String) -> some View {
|
||||||
Text(label)
|
Text(label)
|
||||||
.font(.caption.weight(.medium))
|
.font(.caption.weight(.medium))
|
||||||
|
|
@ -762,12 +834,12 @@ private struct ConfigurationSheetView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !draft.tailnetProvider.usesWebLogin {
|
if availableTailnetAuthModes.count > 1 {
|
||||||
Menu("Authentication") {
|
Menu("Authentication") {
|
||||||
ForEach([AccountAuthMode.none, .password, .preauthKey]) { mode in
|
ForEach(availableTailnetAuthModes) { mode in
|
||||||
Button(mode.title) {
|
Button(mode.title) {
|
||||||
draft.authMode = mode
|
draft.authMode = mode
|
||||||
if mode == .none {
|
if mode == .none || mode == .web {
|
||||||
draft.secret = ""
|
draft.secret = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -848,7 +920,7 @@ private struct ConfigurationSheetView: View {
|
||||||
case .tor:
|
case .tor:
|
||||||
return "Save Account"
|
return "Save Account"
|
||||||
case .tailnet:
|
case .tailnet:
|
||||||
if draft.tailnetProvider.usesWebLogin {
|
if tailnetUsesWebLogin {
|
||||||
return loginStatus?.running == true ? "Save Account" : "Start Sign-In"
|
return loginStatus?.running == true ? "Save Account" : "Start Sign-In"
|
||||||
}
|
}
|
||||||
return "Save Account"
|
return "Save Account"
|
||||||
|
|
@ -865,12 +937,12 @@ private struct ConfigurationSheetView: View {
|
||||||
if normalizedOptional(draft.accountName) == nil || normalizedOptional(draft.identityName) == nil {
|
if normalizedOptional(draft.accountName) == nil || normalizedOptional(draft.identityName) == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if draft.tailnetProvider.usesWebLogin {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if draft.tailnetProvider.requiresControlURL && normalizedOptional(draft.authority) == nil {
|
if draft.tailnetProvider.requiresControlURL && normalizedOptional(draft.authority) == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if tailnetUsesWebLogin {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if draft.authMode != .none && normalizedOptional(draft.secret) == nil {
|
if draft.authMode != .none && normalizedOptional(draft.secret) == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -955,14 +1027,14 @@ private struct ConfigurationSheetView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func submitTailnet() async throws {
|
private func submitTailnet() async throws {
|
||||||
if draft.tailnetProvider.usesWebLogin {
|
if tailnetUsesWebLogin {
|
||||||
if loginStatus?.running == true {
|
if loginStatus?.running == true {
|
||||||
webAuthenticationTask?.cancel()
|
webAuthenticationTask?.cancel()
|
||||||
webAuthenticationTask = nil
|
webAuthenticationTask = nil
|
||||||
try await saveTailnetAccount(secret: nil, username: nil)
|
try await saveTailnetAccount(secret: nil, username: nil)
|
||||||
dismiss()
|
dismiss()
|
||||||
} else {
|
} else {
|
||||||
try await startTailscaleLogin()
|
try await startTailnetLogin()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -973,13 +1045,13 @@ private struct ConfigurationSheetView: View {
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func startTailscaleLogin() async throws {
|
private func startTailnetLogin() async throws {
|
||||||
let response = try await TailnetBridgeClient.startLogin(
|
let response = try await TailnetBridgeClient.startLogin(
|
||||||
TailnetLoginStartRequest(
|
TailnetLoginStartRequest(
|
||||||
accountName: normalized(draft.accountName, fallback: "default"),
|
accountName: normalized(draft.accountName, fallback: "default"),
|
||||||
identityName: normalized(draft.identityName, fallback: "apple"),
|
identityName: normalized(draft.identityName, fallback: "apple"),
|
||||||
hostname: normalizedOptional(draft.hostname),
|
hostname: normalizedOptional(draft.hostname),
|
||||||
controlURL: draft.tailnetProvider.defaultAuthority
|
controlURL: normalizedOptional(draft.authority) ?? draft.tailnetProvider.defaultAuthority
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
loginSessionID = response.sessionID
|
loginSessionID = response.sessionID
|
||||||
|
|
@ -1010,7 +1082,7 @@ private struct ConfigurationSheetView: View {
|
||||||
case .tailnetLogin:
|
case .tailnetLogin:
|
||||||
draft.tailnetProvider = .tailscale
|
draft.tailnetProvider = .tailscale
|
||||||
do {
|
do {
|
||||||
try await startTailscaleLogin()
|
try await startTailnetLogin()
|
||||||
} catch {
|
} catch {
|
||||||
errorMessage = error.localizedDescription
|
errorMessage = error.localizedDescription
|
||||||
}
|
}
|
||||||
|
|
@ -1078,14 +1150,14 @@ private struct ConfigurationSheetView: View {
|
||||||
let provider = draft.tailnetProvider
|
let provider = draft.tailnetProvider
|
||||||
let title = titleOrFallback(
|
let title = titleOrFallback(
|
||||||
hostnameFallback(
|
hostnameFallback(
|
||||||
from: provider.usesWebLogin ? (loginStatus?.tailnetName ?? "") : draft.authority,
|
from: tailnetUsesWebLogin ? (loginStatus?.tailnetName ?? "") : draft.authority,
|
||||||
fallback: provider.title
|
fallback: provider.title
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
let payload = TailnetNetworkPayload(
|
let payload = TailnetNetworkPayload(
|
||||||
provider: provider,
|
provider: provider,
|
||||||
authority: normalizedOptional(provider.defaultAuthority ?? draft.authority),
|
authority: normalizedOptional(draft.authority) ?? normalizedOptional(provider.defaultAuthority ?? ""),
|
||||||
account: normalized(draft.accountName, fallback: "default"),
|
account: normalized(draft.accountName, fallback: "default"),
|
||||||
identity: normalized(draft.identityName, fallback: "apple"),
|
identity: normalized(draft.identityName, fallback: "apple"),
|
||||||
tailnet: normalizedOptional(loginStatus?.tailnetName ?? draft.tailnet),
|
tailnet: normalizedOptional(loginStatus?.tailnetName ?? draft.tailnet),
|
||||||
|
|
@ -1094,7 +1166,7 @@ private struct ConfigurationSheetView: View {
|
||||||
|
|
||||||
var noteParts: [String] = [
|
var noteParts: [String] = [
|
||||||
provider.title,
|
provider.title,
|
||||||
provider.usesWebLogin
|
tailnetUsesWebLogin
|
||||||
? "State: \(loginStatus?.backendState ?? "NeedsLogin")"
|
? "State: \(loginStatus?.backendState ?? "NeedsLogin")"
|
||||||
: "Auth: \(draft.authMode.title)",
|
: "Auth: \(draft.authMode.title)",
|
||||||
]
|
]
|
||||||
|
|
@ -1123,7 +1195,7 @@ private struct ConfigurationSheetView: View {
|
||||||
hostname: payload.hostname,
|
hostname: payload.hostname,
|
||||||
username: username,
|
username: username,
|
||||||
tailnet: payload.tailnet,
|
tailnet: payload.tailnet,
|
||||||
authMode: provider.usesWebLogin ? .web : draft.authMode,
|
authMode: tailnetUsesWebLogin ? .web : draft.authMode,
|
||||||
note: noteParts.joined(separator: " • "),
|
note: noteParts.joined(separator: " • "),
|
||||||
createdAt: .now,
|
createdAt: .now,
|
||||||
updatedAt: .now
|
updatedAt: .now
|
||||||
|
|
@ -1155,18 +1227,25 @@ private struct ConfigurationSheetView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func applyTailnetProvider(_ provider: TailnetProvider) {
|
private func applyTailnetProvider(_ provider: TailnetProvider) {
|
||||||
|
resetTailnetDiscoveryFeedback()
|
||||||
draft.tailnetProvider = provider
|
draft.tailnetProvider = provider
|
||||||
applyTailnetDefaults(for: provider)
|
applyTailnetDefaults(for: provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func applyTailnetDefaults(for provider: TailnetProvider) {
|
private func applyTailnetDefaults(for provider: TailnetProvider) {
|
||||||
draft.authority = provider.defaultAuthority ?? ""
|
draft.authority = provider.defaultAuthority ?? ""
|
||||||
if provider.usesWebLogin {
|
loginStatus = nil
|
||||||
|
loginSessionID = nil
|
||||||
|
pollingTask?.cancel()
|
||||||
|
if provider == .tailscale {
|
||||||
draft.authMode = .web
|
draft.authMode = .web
|
||||||
draft.username = ""
|
draft.username = ""
|
||||||
draft.secret = ""
|
draft.secret = ""
|
||||||
} else {
|
} else {
|
||||||
if draft.authMode == .web {
|
if !availableTailnetAuthModes.contains(draft.authMode) {
|
||||||
|
draft.authMode = provider.supportsWebLogin ? .web : .none
|
||||||
|
}
|
||||||
|
if draft.authMode == .web && !provider.supportsWebLogin {
|
||||||
draft.authMode = .none
|
draft.authMode = .none
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1202,6 +1281,41 @@ private struct ConfigurationSheetView: View {
|
||||||
authorityProbeError = nil
|
authorityProbeError = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func resetTailnetDiscoveryFeedback() {
|
||||||
|
discoveryStatus = nil
|
||||||
|
discoveryError = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func discoverTailnetAuthority() {
|
||||||
|
guard let email = normalizedOptional(draft.discoveryEmail) else {
|
||||||
|
discoveryStatus = nil
|
||||||
|
discoveryError = "Enter an email address first."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isDiscoveringTailnet = true
|
||||||
|
discoveryStatus = nil
|
||||||
|
discoveryError = nil
|
||||||
|
|
||||||
|
Task { @MainActor in
|
||||||
|
defer { isDiscoveringTailnet = false }
|
||||||
|
do {
|
||||||
|
let discovery = try await TailnetDiscoveryClient.discover(email: email)
|
||||||
|
discoveryStatus = discovery
|
||||||
|
draft.tailnetProvider = discovery.provider
|
||||||
|
draft.authority = discovery.authority
|
||||||
|
if discovery.provider.supportsWebLogin, discovery.oidcIssuer != nil {
|
||||||
|
draft.authMode = .web
|
||||||
|
draft.username = ""
|
||||||
|
draft.secret = ""
|
||||||
|
}
|
||||||
|
probeTailnetAuthority()
|
||||||
|
} catch {
|
||||||
|
discoveryError = error.localizedDescription
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func pasteWireGuardConfiguration() {
|
private func pasteWireGuardConfiguration() {
|
||||||
guard let clipboardString else { return }
|
guard let clipboardString else { return }
|
||||||
draft.wireGuardConfig = clipboardString
|
draft.wireGuardConfig = clipboardString
|
||||||
|
|
@ -1247,6 +1361,21 @@ private struct ConfigurationSheetView: View {
|
||||||
return host
|
return host
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var tailnetUsesWebLogin: Bool {
|
||||||
|
draft.authMode == .web && draft.tailnetProvider.supportsWebLogin
|
||||||
|
}
|
||||||
|
|
||||||
|
private var availableTailnetAuthModes: [AccountAuthMode] {
|
||||||
|
switch draft.tailnetProvider {
|
||||||
|
case .tailscale:
|
||||||
|
[.web]
|
||||||
|
case .headscale:
|
||||||
|
[.web, .none, .password, .preauthKey]
|
||||||
|
case .burrow:
|
||||||
|
[.none, .password, .preauthKey]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private func labeledValue(_ label: String, _ value: String) -> some View {
|
private func labeledValue(_ label: String, _ value: String) -> some View {
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,13 @@ struct TailnetLoginStartRequest: Codable, Sendable {
|
||||||
var controlURL: String?
|
var controlURL: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TailnetDiscoveryResponse: Codable, Sendable {
|
||||||
|
var domain: String
|
||||||
|
var provider: TailnetProvider
|
||||||
|
var authority: String
|
||||||
|
var oidcIssuer: String?
|
||||||
|
}
|
||||||
|
|
||||||
struct TailnetLoginStatus: Codable, Sendable {
|
struct TailnetLoginStatus: Codable, Sendable {
|
||||||
var backendState: String
|
var backendState: String
|
||||||
var authURL: String?
|
var authURL: String?
|
||||||
|
|
@ -91,7 +98,7 @@ enum TailnetBridgeClient {
|
||||||
return try decoder.decode(TailnetLoginStatus.self, from: data)
|
return try decoder.decode(TailnetLoginStatus.self, from: data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func validate(response: URLResponse, data: Data) throws {
|
fileprivate static func validate(response: URLResponse, data: Data) throws {
|
||||||
guard let http = response as? HTTPURLResponse else {
|
guard let http = response as? HTTPURLResponse else {
|
||||||
throw URLError(.badServerResponse)
|
throw URLError(.badServerResponse)
|
||||||
}
|
}
|
||||||
|
|
@ -104,6 +111,32 @@ enum TailnetBridgeClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum TailnetDiscoveryClient {
|
||||||
|
private static let baseURL = URL(string: "http://127.0.0.1:8080")!
|
||||||
|
|
||||||
|
static func discover(email: String) async throws -> TailnetDiscoveryResponse {
|
||||||
|
guard var components = URLComponents(
|
||||||
|
url: baseURL.appendingPathComponent("v1/tailnet/discover"),
|
||||||
|
resolvingAgainstBaseURL: false
|
||||||
|
) else {
|
||||||
|
throw URLError(.badURL)
|
||||||
|
}
|
||||||
|
components.queryItems = [
|
||||||
|
URLQueryItem(name: "email", value: email)
|
||||||
|
]
|
||||||
|
guard let url = components.url else {
|
||||||
|
throw URLError(.badURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
let (data, response) = try await URLSession.shared.data(from: url)
|
||||||
|
try TailnetBridgeClient.validate(response: response, data: data)
|
||||||
|
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
decoder.keyDecodingStrategy = .convertFromSnakeCase
|
||||||
|
return try decoder.decode(TailnetDiscoveryResponse.self, from: data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum TailnetAuthorityProbeClient {
|
enum TailnetAuthorityProbeClient {
|
||||||
static func probe(provider: TailnetProvider, authority: String) async throws -> TailnetAuthorityProbeStatus {
|
static func probe(provider: TailnetProvider, authority: String) async throws -> TailnetAuthorityProbeStatus {
|
||||||
let normalizedAuthority = normalizeAuthority(authority)
|
let normalizedAuthority = normalizeAuthority(authority)
|
||||||
|
|
@ -308,8 +341,13 @@ enum TailnetProvider: String, CaseIterable, Codable, Identifiable, Sendable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var usesWebLogin: Bool {
|
var supportsWebLogin: Bool {
|
||||||
self == .tailscale
|
switch self {
|
||||||
|
case .tailscale, .headscale:
|
||||||
|
true
|
||||||
|
case .burrow:
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var requiresControlURL: Bool {
|
var requiresControlURL: Bool {
|
||||||
|
|
@ -332,7 +370,7 @@ enum TailnetProvider: String, CaseIterable, Codable, Identifiable, Sendable {
|
||||||
case .tailscale:
|
case .tailscale:
|
||||||
"Use Tailscale's real browser login flow."
|
"Use Tailscale's real browser login flow."
|
||||||
case .headscale:
|
case .headscale:
|
||||||
"Store a Headscale control-plane endpoint and credentials."
|
"Use your Headscale control plane with browser or key-based sign-in."
|
||||||
case .burrow:
|
case .burrow:
|
||||||
"Store Burrow control-plane credentials."
|
"Store Burrow control-plane credentials."
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,18 @@ use std::{env, path::Path};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Json, Path as AxumPath, State},
|
extract::{Json, Path as AxumPath, Query, State},
|
||||||
http::{header::AUTHORIZATION, HeaderMap, StatusCode},
|
http::{header::AUTHORIZATION, HeaderMap, StatusCode},
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
|
use serde::Deserialize;
|
||||||
use tokio::signal;
|
use tokio::signal;
|
||||||
|
|
||||||
use crate::control::{
|
use crate::control::{
|
||||||
LocalAuthRequest, LocalAuthResponse, MapRequest, MapResponse, RegisterRequest,
|
discovery, LocalAuthRequest, LocalAuthResponse, MapRequest, MapResponse, RegisterRequest,
|
||||||
RegisterResponse, BURROW_TAILNET_DOMAIN,
|
RegisterResponse, TailnetDiscovery, BURROW_TAILNET_DOMAIN,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -105,6 +106,11 @@ struct AppState {
|
||||||
tailscale: tailscale::TailscaleBridgeManager,
|
tailscale: tailscale::TailscaleBridgeManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct TailnetDiscoveryQuery {
|
||||||
|
email: String,
|
||||||
|
}
|
||||||
|
|
||||||
type AppResult<T> = Result<T, (StatusCode, String)>;
|
type AppResult<T> = Result<T, (StatusCode, String)>;
|
||||||
|
|
||||||
pub async fn serve() -> Result<()> {
|
pub async fn serve() -> Result<()> {
|
||||||
|
|
@ -139,6 +145,7 @@ pub fn build_router(config: AuthServerConfig) -> Router {
|
||||||
.route("/v1/auth/login", post(login_local))
|
.route("/v1/auth/login", post(login_local))
|
||||||
.route("/v1/control/register", post(control_register))
|
.route("/v1/control/register", post(control_register))
|
||||||
.route("/v1/control/map", post(control_map))
|
.route("/v1/control/map", post(control_map))
|
||||||
|
.route("/v1/tailnet/discover", get(tailnet_discover))
|
||||||
.route("/v1/tailscale/login/start", post(tailscale_login_start))
|
.route("/v1/tailscale/login/start", post(tailscale_login_start))
|
||||||
.route("/v1/tailscale/login/:session_id", get(tailscale_login_status))
|
.route("/v1/tailscale/login/:session_id", get(tailscale_login_status))
|
||||||
.with_state(AppState {
|
.with_state(AppState {
|
||||||
|
|
@ -205,6 +212,19 @@ async fn control_map(
|
||||||
Ok(Json(response))
|
Ok(Json(response))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn tailnet_discover(
|
||||||
|
Query(query): Query<TailnetDiscoveryQuery>,
|
||||||
|
) -> AppResult<Json<TailnetDiscovery>> {
|
||||||
|
if query.email.trim().is_empty() {
|
||||||
|
return Err((StatusCode::BAD_REQUEST, "email is required".to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let discovery = discovery::discover_tailnet(&query.email)
|
||||||
|
.await
|
||||||
|
.map_err(|err| (StatusCode::BAD_GATEWAY, err.to_string()))?;
|
||||||
|
Ok(Json(discovery))
|
||||||
|
}
|
||||||
|
|
||||||
async fn tailscale_login_start(
|
async fn tailscale_login_start(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Json(request): Json<tailscale::TailscaleLoginStartRequest>,
|
Json(request): Json<tailscale::TailscaleLoginStartRequest>,
|
||||||
|
|
@ -394,4 +414,17 @@ mod tests {
|
||||||
assert!(map.dns.expect("dns").magic_dns);
|
assert!(map.dns.expect("dns").magic_dns);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn tailnet_discover_requires_email() -> Result<()> {
|
||||||
|
let app = build_router(AuthServerConfig::default());
|
||||||
|
let response = app
|
||||||
|
.oneshot(
|
||||||
|
Request::get("/v1/tailnet/discover?email=")
|
||||||
|
.body(Body::empty())?,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
212
burrow/src/control/discovery.rs
Normal file
212
burrow/src/control/discovery.rs
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
use reqwest::{Client, StatusCode, Url};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::TailnetProvider;
|
||||||
|
|
||||||
|
pub const TAILNET_DISCOVERY_REL: &str = "https://burrow.net/rel/tailnet-control-server";
|
||||||
|
const TAILNET_DISCOVERY_PATH: &str = "/.well-known/burrow-tailnet";
|
||||||
|
const WEBFINGER_PATH: &str = "/.well-known/webfinger";
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct TailnetDiscovery {
|
||||||
|
pub domain: String,
|
||||||
|
pub provider: TailnetProvider,
|
||||||
|
pub authority: String,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub oidc_issuer: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Deserialize)]
|
||||||
|
struct WebFingerDocument {
|
||||||
|
#[serde(default)]
|
||||||
|
links: Vec<WebFingerLink>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Deserialize)]
|
||||||
|
struct WebFingerLink {
|
||||||
|
#[serde(default)]
|
||||||
|
rel: String,
|
||||||
|
#[serde(default)]
|
||||||
|
href: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn discover_tailnet(email: &str) -> Result<TailnetDiscovery> {
|
||||||
|
let domain = email_domain(email)?;
|
||||||
|
let base_url = Url::parse(&format!("https://{domain}"))
|
||||||
|
.with_context(|| format!("invalid discovery domain {domain}"))?;
|
||||||
|
let client = Client::builder()
|
||||||
|
.user_agent("burrow-tailnet-discovery")
|
||||||
|
.timeout(std::time::Duration::from_secs(10))
|
||||||
|
.build()
|
||||||
|
.context("failed to build tailnet discovery client")?;
|
||||||
|
discover_tailnet_at(&client, email, &base_url).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn discover_tailnet_at(
|
||||||
|
client: &Client,
|
||||||
|
email: &str,
|
||||||
|
base_url: &Url,
|
||||||
|
) -> Result<TailnetDiscovery> {
|
||||||
|
let domain = email_domain(email)?;
|
||||||
|
|
||||||
|
if let Some(discovery) = discover_well_known(client, base_url).await? {
|
||||||
|
return Ok(TailnetDiscovery { domain, ..discovery });
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(authority) = discover_webfinger(client, email, base_url).await? {
|
||||||
|
return Ok(TailnetDiscovery {
|
||||||
|
domain,
|
||||||
|
provider: TailnetProvider::Headscale,
|
||||||
|
authority,
|
||||||
|
oidc_issuer: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(anyhow!("no tailnet discovery metadata found for {domain}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn email_domain(email: &str) -> Result<String> {
|
||||||
|
let trimmed = email.trim();
|
||||||
|
let (_, domain) = trimmed
|
||||||
|
.rsplit_once('@')
|
||||||
|
.ok_or_else(|| anyhow!("email address must include a domain"))?;
|
||||||
|
let domain = domain.trim().trim_matches('.').to_ascii_lowercase();
|
||||||
|
if domain.is_empty() {
|
||||||
|
return Err(anyhow!("email address must include a domain"));
|
||||||
|
}
|
||||||
|
Ok(domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn discover_well_known(client: &Client, base_url: &Url) -> Result<Option<TailnetDiscovery>> {
|
||||||
|
let url = base_url
|
||||||
|
.join(TAILNET_DISCOVERY_PATH)
|
||||||
|
.context("failed to build tailnet discovery URL")?;
|
||||||
|
let response = client
|
||||||
|
.get(url)
|
||||||
|
.header("accept", "application/json")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.context("tailnet well-known request failed")?;
|
||||||
|
|
||||||
|
match response.status() {
|
||||||
|
StatusCode::OK => response
|
||||||
|
.json::<TailnetDiscovery>()
|
||||||
|
.await
|
||||||
|
.context("invalid tailnet discovery document")
|
||||||
|
.map(Some),
|
||||||
|
StatusCode::NOT_FOUND => Ok(None),
|
||||||
|
status => Err(anyhow!("tailnet well-known lookup failed with HTTP {status}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn discover_webfinger(client: &Client, email: &str, base_url: &Url) -> Result<Option<String>> {
|
||||||
|
let mut url = base_url
|
||||||
|
.join(WEBFINGER_PATH)
|
||||||
|
.context("failed to build webfinger URL")?;
|
||||||
|
url.query_pairs_mut()
|
||||||
|
.append_pair("resource", &format!("acct:{email}"))
|
||||||
|
.append_pair("rel", TAILNET_DISCOVERY_REL);
|
||||||
|
|
||||||
|
let response = client
|
||||||
|
.get(url)
|
||||||
|
.header("accept", "application/jrd+json, application/json")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.context("tailnet webfinger request failed")?;
|
||||||
|
|
||||||
|
match response.status() {
|
||||||
|
StatusCode::OK => {
|
||||||
|
let document = response
|
||||||
|
.json::<WebFingerDocument>()
|
||||||
|
.await
|
||||||
|
.context("invalid webfinger document")?;
|
||||||
|
Ok(document
|
||||||
|
.links
|
||||||
|
.into_iter()
|
||||||
|
.find(|link| link.rel == TAILNET_DISCOVERY_REL)
|
||||||
|
.and_then(|link| link.href)
|
||||||
|
.filter(|href| !href.trim().is_empty()))
|
||||||
|
}
|
||||||
|
StatusCode::NOT_FOUND => Ok(None),
|
||||||
|
status => Err(anyhow!("tailnet webfinger lookup failed with HTTP {status}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use axum::{routing::get, Router};
|
||||||
|
use serde_json::json;
|
||||||
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extracts_domain_from_email() {
|
||||||
|
assert_eq!(email_domain("Contact@Burrow.net").unwrap(), "burrow.net");
|
||||||
|
assert!(email_domain("contact").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn discovers_from_well_known_document() -> Result<()> {
|
||||||
|
let router = Router::new().route(
|
||||||
|
TAILNET_DISCOVERY_PATH,
|
||||||
|
get(|| async {
|
||||||
|
axum::Json(json!({
|
||||||
|
"domain": "burrow.net",
|
||||||
|
"provider": "headscale",
|
||||||
|
"authority": "https://ts.burrow.net",
|
||||||
|
"oidc_issuer": "https://auth.burrow.net/application/o/ts/"
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let listener = TcpListener::bind("127.0.0.1:0").await?;
|
||||||
|
let base_url = Url::parse(&format!("http://{}", listener.local_addr()?))?;
|
||||||
|
let server = tokio::spawn(async move { axum::serve(listener, router).await });
|
||||||
|
|
||||||
|
let client = Client::builder().build()?;
|
||||||
|
let discovery = discover_tailnet_at(&client, "contact@burrow.net", &base_url).await?;
|
||||||
|
assert_eq!(discovery.provider, TailnetProvider::Headscale);
|
||||||
|
assert_eq!(discovery.authority, "https://ts.burrow.net");
|
||||||
|
assert_eq!(discovery.domain, "burrow.net");
|
||||||
|
|
||||||
|
server.abort();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn falls_back_to_webfinger_authority() -> Result<()> {
|
||||||
|
let router = Router::new()
|
||||||
|
.route(
|
||||||
|
TAILNET_DISCOVERY_PATH,
|
||||||
|
get(|| async { (StatusCode::NOT_FOUND, "") }),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
WEBFINGER_PATH,
|
||||||
|
get(|| async {
|
||||||
|
axum::Json(json!({
|
||||||
|
"subject": "acct:contact@burrow.net",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"rel": TAILNET_DISCOVERY_REL,
|
||||||
|
"href": "https://ts.burrow.net"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let listener = TcpListener::bind("127.0.0.1:0").await?;
|
||||||
|
let base_url = Url::parse(&format!("http://{}", listener.local_addr()?))?;
|
||||||
|
let server = tokio::spawn(async move { axum::serve(listener, router).await });
|
||||||
|
|
||||||
|
let client = Client::builder().build()?;
|
||||||
|
let discovery = discover_tailnet_at(&client, "contact@burrow.net", &base_url).await?;
|
||||||
|
assert_eq!(discovery.provider, TailnetProvider::Headscale);
|
||||||
|
assert_eq!(discovery.authority, "https://ts.burrow.net");
|
||||||
|
|
||||||
|
server.abort();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod discovery;
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
|
@ -6,6 +7,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
pub use config::{TailnetConfig, TailnetProvider};
|
pub use config::{TailnetConfig, TailnetProvider};
|
||||||
|
pub use discovery::{TailnetDiscovery, TAILNET_DISCOVERY_REL};
|
||||||
|
|
||||||
pub const BURROW_CAPABILITY_VERSION: i32 = 1;
|
pub const BURROW_CAPABILITY_VERSION: i32 = 1;
|
||||||
pub const BURROW_TAILNET_DOMAIN: &str = "burrow.net";
|
pub const BURROW_TAILNET_DOMAIN: &str = "burrow.net";
|
||||||
|
|
|
||||||
|
|
@ -259,9 +259,12 @@ in
|
||||||
encode gzip zstd
|
encode gzip zstd
|
||||||
@oidcConfig path /.well-known/openid-configuration
|
@oidcConfig path /.well-known/openid-configuration
|
||||||
redir @oidcConfig https://${config.services.burrow.authentik.domain}/application/o/${config.services.burrow.authentik.forgejoProviderSlug}/.well-known/openid-configuration 308
|
redir @oidcConfig https://${config.services.burrow.authentik.domain}/application/o/${config.services.burrow.authentik.forgejoProviderSlug}/.well-known/openid-configuration 308
|
||||||
|
@tailnetConfig path /.well-known/burrow-tailnet
|
||||||
|
header @tailnetConfig Content-Type application/json
|
||||||
|
respond @tailnetConfig "{\"domain\":\"${cfg.siteDomain}\",\"provider\":\"headscale\",\"authority\":\"https://${config.services.burrow.headscale.domain}\",\"oidc_issuer\":\"https://${config.services.burrow.authentik.domain}/application/o/${config.services.burrow.authentik.headscaleProviderSlug}/\"}" 200
|
||||||
@webfinger path /.well-known/webfinger
|
@webfinger path /.well-known/webfinger
|
||||||
header @webfinger Content-Type application/jrd+json
|
header @webfinger Content-Type application/jrd+json
|
||||||
respond @webfinger "{\"subject\":\"{query.resource}\",\"links\":[{\"rel\":\"http://openid.net/specs/connect/1.0/issuer\",\"href\":\"https://${config.services.burrow.authentik.domain}/application/o/${config.services.burrow.authentik.forgejoProviderSlug}/\"}]}" 200
|
respond @webfinger "{\"subject\":\"{query.resource}\",\"links\":[{\"rel\":\"http://openid.net/specs/connect/1.0/issuer\",\"href\":\"https://${config.services.burrow.authentik.domain}/application/o/${config.services.burrow.authentik.forgejoProviderSlug}/\"},{\"rel\":\"https://burrow.net/rel/tailnet-control-server\",\"href\":\"https://${config.services.burrow.headscale.domain}\"}]}" 200
|
||||||
@root path /
|
@root path /
|
||||||
redir @root ${homeRepoUrl} 308
|
redir @root ${homeRepoUrl} 308
|
||||||
respond 404
|
respond 404
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue