openTunnel method
- required int targetPort,
- String nodeId = '',
- String targetHost = 'localhost',
- int? publicPort,
- bool local = false,
- bool secure = false,
- TunnelProtocol protocol = TunnelProtocol.tcp,
- TunnelCacheOptions? cache,
- TunnelHttpTimeouts? timeouts,
Opens a tunnel that exposes targetPort — reachable by nodeId, or this
client's own machine when local is set — on a public Hub port. When
publicPort is given the Hub validates it against its configured range;
otherwise the Hub allocates one in range. Completes once the Hub confirms,
or throws TunnelRejectedException if refused.
For a local tunnel this client must stay connected to serve the forwarded
connections (it dials its own targetHost:targetPort for each).
With protocol TunnelProtocol.http the Hub adds forwarding headers
(X-Forwarded-*, Forwarded, X-Real-IP, Via, X-Request-Id and
X-OmnyShell-*) to every request it relays to the target. Check the
returned TunnelHandle.protocol: an older Hub opens it as plain TCP.
An HTTP tunnel can also keep an in-memory response cache on the Hub
(RFC 9111; the Hub clamps its size — see TunnelHandle.cache for what was
granted) and enforces timeouts (the Hub's defaults when null). Both
require TunnelProtocol.http; the Hub rejects them otherwise.
Implementation
Future<TunnelHandle> openTunnel({
required int targetPort,
String nodeId = '',
String targetHost = 'localhost',
int? publicPort,
bool local = false,
bool secure = false,
TunnelProtocol protocol = TunnelProtocol.tcp,
TunnelCacheOptions? cache,
TunnelHttpTimeouts? timeouts,
}) {
_ensureConnected();
final id = newId();
final effectiveNode = local ? TunnelOpenRequest.localNode : nodeId;
final completer = Completer<TunnelHandle>();
_pendingTunnelOpens[id] = (
completer: completer,
nodeId: effectiveNode,
targetPort: targetPort,
);
_connection!.send(
ControlFrame(
TunnelOpenRequest(
requestId: id,
nodeId: effectiveNode,
targetHost: targetHost,
targetPort: targetPort,
publicPort: publicPort,
secure: secure,
protocol: protocol,
cache: cache,
timeouts: timeouts,
),
),
);
return _rpcTimeout(
completer.future,
() => _pendingTunnelOpens.remove(id),
what: 'node "$effectiveNode"',
timeout: const Duration(seconds: 30),
);
}