Skip to content

Commit 1001653

Browse files
authored
HTTP CONNECT proxy support (#501)
1 parent 466da16 commit 1001653

File tree

7 files changed

+61
-6
lines changed

7 files changed

+61
-6
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,4 @@ jobs:
9494
python-repo-path: ${{github.event.pull_request.head.repo.full_name}}
9595
version: ${{github.event.pull_request.head.ref}}
9696
version-is-repo-ref: true
97+
features-repo-ref: http-connect-proxy-python

temporalio/bridge/Cargo.lock

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

temporalio/bridge/client.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from dataclasses import dataclass
99
from datetime import timedelta
10-
from typing import Mapping, Optional, Type, TypeVar
10+
from typing import Mapping, Optional, Tuple, Type, TypeVar
1111

1212
import google.protobuf.message
1313

@@ -46,6 +46,14 @@ class ClientKeepAliveConfig:
4646
timeout_millis: int
4747

4848

49+
@dataclass
50+
class ClientHttpConnectProxyConfig:
51+
"""Python representation of the Rust struct for configuring HTTP proxy."""
52+
53+
target_host: str
54+
basic_auth: Optional[Tuple[str, str]]
55+
56+
4957
@dataclass
5058
class ClientConfig:
5159
"""Python representation of the Rust struct for configuring the client."""
@@ -59,6 +67,7 @@ class ClientConfig:
5967
keep_alive_config: Optional[ClientKeepAliveConfig]
6068
client_name: str
6169
client_version: str
70+
http_connect_proxy_config: Optional[ClientHttpConnectProxyConfig]
6271

6372

6473
@dataclass

temporalio/bridge/src/client.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::time::Duration;
66
use temporal_client::{
77
ClientKeepAliveConfig as CoreClientKeepAliveConfig, ClientOptions, ClientOptionsBuilder,
88
ConfiguredClient, HealthService, OperatorService, RetryClient, RetryConfig,
9-
TemporalServiceClientWithMetrics, TestService, TlsConfig, WorkflowService,
9+
TemporalServiceClientWithMetrics, TestService, TlsConfig, WorkflowService, HttpConnectProxyOptions,
1010
};
1111
use tonic::metadata::MetadataKey;
1212
use url::Url;
@@ -34,6 +34,7 @@ pub struct ClientConfig {
3434
tls_config: Option<ClientTlsConfig>,
3535
retry_config: Option<ClientRetryConfig>,
3636
keep_alive_config: Option<ClientKeepAliveConfig>,
37+
http_connect_proxy_config: Option<ClientHttpConnectProxyConfig>,
3738
}
3839

3940
#[derive(FromPyObject)]
@@ -60,6 +61,12 @@ struct ClientKeepAliveConfig {
6061
pub timeout_millis: u64,
6162
}
6263

64+
#[derive(FromPyObject)]
65+
struct ClientHttpConnectProxyConfig {
66+
pub target_host: String,
67+
pub basic_auth: Option<(String, String)>,
68+
}
69+
6370
#[derive(FromPyObject)]
6471
struct RpcCall {
6572
rpc: String,
@@ -392,6 +399,7 @@ impl TryFrom<ClientConfig> for ClientOptions {
392399
.map_or(RetryConfig::default(), |c| c.into()),
393400
)
394401
.keep_alive(opts.keep_alive_config.map(Into::into))
402+
.http_connect_proxy(opts.http_connect_proxy_config.map(Into::into))
395403
.headers(Some(opts.metadata))
396404
.api_key(opts.api_key);
397405
// Builder does not allow us to set option here, so we have to make
@@ -451,3 +459,12 @@ impl From<ClientKeepAliveConfig> for CoreClientKeepAliveConfig {
451459
}
452460
}
453461
}
462+
463+
impl From<ClientHttpConnectProxyConfig> for HttpConnectProxyOptions {
464+
fn from(conf: ClientHttpConnectProxyConfig) -> Self {
465+
HttpConnectProxyOptions {
466+
target_addr: conf.target_host,
467+
basic_auth: conf.basic_auth,
468+
}
469+
}
470+
}

temporalio/client.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import temporalio.service
5555
import temporalio.workflow
5656
from temporalio.service import (
57+
HttpConnectProxyConfig,
5758
KeepAliveConfig,
5859
RetryConfig,
5960
RPCError,
@@ -110,6 +111,7 @@ async def connect(
110111
identity: Optional[str] = None,
111112
lazy: bool = False,
112113
runtime: Optional[temporalio.runtime.Runtime] = None,
114+
http_connect_proxy_config: Optional[HttpConnectProxyConfig] = None,
113115
) -> Client:
114116
"""Connect to a Temporal server.
115117
@@ -153,6 +155,7 @@ async def connect(
153155
attempted or a worker is created with it. Lazy clients cannot be
154156
used for workers.
155157
runtime: The runtime for this client, or the default if unset.
158+
http_connect_proxy_config: Configuration for HTTP CONNECT proxy.
156159
"""
157160
connect_config = temporalio.service.ConnectConfig(
158161
target_host=target_host,
@@ -164,6 +167,7 @@ async def connect(
164167
identity=identity or "",
165168
lazy=lazy,
166169
runtime=runtime,
170+
http_connect_proxy_config=http_connect_proxy_config,
167171
)
168172
return Client(
169173
await temporalio.service.ServiceClient.connect(connect_config),

temporalio/service.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from dataclasses import dataclass, field
1212
from datetime import timedelta
1313
from enum import IntEnum
14-
from typing import ClassVar, Generic, Mapping, Optional, Type, TypeVar, Union
14+
from typing import ClassVar, Generic, Mapping, Optional, Tuple, Type, TypeVar, Union
1515

1616
import google.protobuf.empty_pb2
1717
import google.protobuf.message
@@ -115,6 +115,24 @@ def _to_bridge_config(self) -> temporalio.bridge.client.ClientKeepAliveConfig:
115115
KeepAliveConfig.default = KeepAliveConfig()
116116

117117

118+
@dataclass(frozen=True)
119+
class HttpConnectProxyConfig:
120+
"""Configuration for HTTP CONNECT proxy for client connections."""
121+
122+
target_host: str
123+
"""Target host:port for the HTTP CONNECT proxy."""
124+
basic_auth: Optional[Tuple[str, str]] = None
125+
"""Basic auth for the HTTP CONNECT proxy if any as a user/pass tuple."""
126+
127+
def _to_bridge_config(
128+
self,
129+
) -> temporalio.bridge.client.ClientHttpConnectProxyConfig:
130+
return temporalio.bridge.client.ClientHttpConnectProxyConfig(
131+
target_host=self.target_host,
132+
basic_auth=self.basic_auth,
133+
)
134+
135+
118136
@dataclass
119137
class ConnectConfig:
120138
"""Config for connecting to the server."""
@@ -128,6 +146,7 @@ class ConnectConfig:
128146
identity: str = ""
129147
lazy: bool = False
130148
runtime: Optional[temporalio.runtime.Runtime] = None
149+
http_connect_proxy_config: Optional[HttpConnectProxyConfig] = None
131150

132151
def __post_init__(self) -> None:
133152
"""Set extra defaults on unset properties."""
@@ -174,6 +193,9 @@ def _to_bridge_config(self) -> temporalio.bridge.client.ClientConfig:
174193
identity=self.identity,
175194
client_name="temporal-python",
176195
client_version=__version__,
196+
http_connect_proxy_config=self.http_connect_proxy_config._to_bridge_config()
197+
if self.http_connect_proxy_config
198+
else None,
177199
)
178200

179201

0 commit comments

Comments
 (0)