embed-client 1.0.1.1__py3-none-any.whl → 3.1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- embed_client/async_client.py +445 -22
- embed_client/auth.py +487 -0
- embed_client/auth_examples.py +248 -0
- embed_client/client_factory.py +396 -0
- embed_client/client_factory_examples.py +353 -0
- embed_client/config.py +592 -0
- embed_client/config_examples.py +197 -0
- embed_client/example_async_usage.py +578 -90
- embed_client/example_async_usage_ru.py +442 -92
- embed_client/ssl_examples.py +329 -0
- embed_client/ssl_manager.py +466 -0
- embed_client-3.1.0.0.dist-info/METADATA +229 -0
- embed_client-3.1.0.0.dist-info/RECORD +16 -0
- embed_client-1.0.1.1.dist-info/METADATA +0 -9
- embed_client-1.0.1.1.dist-info/RECORD +0 -8
- {embed_client-1.0.1.1.dist-info → embed_client-3.1.0.0.dist-info}/WHEEL +0 -0
- {embed_client-1.0.1.1.dist-info → embed_client-3.1.0.0.dist-info}/top_level.txt +0 -0
@@ -1,71 +1,312 @@
|
|
1
1
|
"""
|
2
|
-
Example usage of EmbeddingServiceAsyncClient.
|
2
|
+
Example usage of EmbeddingServiceAsyncClient with all security modes and ClientFactory.
|
3
|
+
|
4
|
+
Author: Vasiliy Zdanovskiy
|
5
|
+
email: vasilyvz@gmail.com
|
6
|
+
|
7
|
+
This example demonstrates all 6 security modes supported by the embed-client:
|
8
|
+
1. HTTP (plain HTTP without authentication)
|
9
|
+
2. HTTP + Token (HTTP with API key authentication)
|
10
|
+
3. HTTPS (HTTPS with server certificate verification)
|
11
|
+
4. HTTPS + Token (HTTPS with server certificates + authentication)
|
12
|
+
5. mTLS (mutual TLS with client and server certificates)
|
13
|
+
6. mTLS + Roles (mTLS with role-based access control)
|
3
14
|
|
4
15
|
USAGE:
|
16
|
+
# Basic usage without authentication
|
5
17
|
python embed_client/example_async_usage.py --base-url http://localhost --port 8001
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
18
|
+
|
19
|
+
# With API key authentication
|
20
|
+
python embed_client/example_async_usage.py --base-url http://localhost --port 8001 --auth-method api_key --api-key your_key
|
21
|
+
|
22
|
+
# With JWT authentication
|
23
|
+
python embed_client/example_async_usage.py --base-url http://localhost --port 8001 --auth-method jwt --jwt-secret secret --jwt-username user
|
24
|
+
|
25
|
+
# With basic authentication
|
26
|
+
python embed_client/example_async_usage.py --base-url http://localhost --port 8001 --auth-method basic --username user --password pass
|
27
|
+
|
28
|
+
# With configuration file
|
29
|
+
python embed_client/example_async_usage.py --config configs/http_token.json
|
30
|
+
|
31
|
+
# With environment variables
|
10
32
|
export EMBED_CLIENT_BASE_URL=http://localhost
|
11
33
|
export EMBED_CLIENT_PORT=8001
|
34
|
+
export EMBED_CLIENT_AUTH_METHOD=api_key
|
35
|
+
export EMBED_CLIENT_API_KEY=your_key
|
12
36
|
python embed_client/example_async_usage.py
|
13
37
|
|
14
|
-
|
15
|
-
#
|
16
|
-
# а не через = (НЕ --base_url=...)
|
17
|
-
# base_url должен содержать http:// или https://
|
18
|
-
|
19
|
-
EXAMPLES:
|
38
|
+
SECURITY MODES EXAMPLES:
|
39
|
+
# 1. HTTP - plain HTTP without authentication
|
20
40
|
python embed_client/example_async_usage.py --base-url http://localhost --port 8001
|
21
|
-
|
22
|
-
|
23
|
-
|
41
|
+
|
42
|
+
# 2. HTTP + Token - HTTP with API key authentication
|
43
|
+
python embed_client/example_async_usage.py --base-url http://localhost --port 8001 --auth-method api_key --api-key admin_key_123
|
44
|
+
|
45
|
+
# 3. HTTPS - HTTPS with server certificate verification
|
46
|
+
python embed_client/example_async_usage.py --base-url https://localhost --port 9443
|
47
|
+
|
48
|
+
# 4. HTTPS + Token - HTTPS with server certificates + authentication
|
49
|
+
python embed_client/example_async_usage.py --base-url https://localhost --port 9443 --auth-method jwt --jwt-secret secret --jwt-username admin
|
50
|
+
|
51
|
+
# 5. mTLS - mutual TLS with client and server certificates
|
52
|
+
python embed_client/example_async_usage.py --base-url https://localhost --port 9443 --cert-file certs/client.crt --key-file keys/client.key
|
53
|
+
|
54
|
+
# 6. mTLS + Roles - mTLS with role-based access control
|
55
|
+
python embed_client/example_async_usage.py --base-url https://localhost --port 9443 --cert-file certs/client.crt --key-file keys/client.key --roles admin,user
|
56
|
+
|
57
|
+
CLIENT FACTORY EXAMPLES:
|
58
|
+
# Automatic security mode detection
|
59
|
+
python embed_client/example_async_usage.py --factory-mode auto --base-url https://localhost --port 9443 --auth-method api_key --api-key key
|
60
|
+
|
61
|
+
# Specific security mode creation
|
62
|
+
python embed_client/example_async_usage.py --factory-mode https_token --base-url https://localhost --port 9443 --auth-method basic --username user --password pass
|
63
|
+
|
64
|
+
# mTLS with factory
|
65
|
+
python embed_client/example_async_usage.py --factory-mode mtls --base-url https://localhost --port 9443 --cert-file certs/client.crt --key-file keys/client.key
|
66
|
+
|
67
|
+
SSL/TLS EXAMPLES:
|
68
|
+
# HTTPS with SSL verification disabled
|
69
|
+
python embed_client/example_async_usage.py --base-url https://localhost --port 9443 --ssl-verify-mode CERT_NONE
|
70
|
+
|
71
|
+
# mTLS with custom CA certificate
|
72
|
+
python embed_client/example_async_usage.py --base-url https://localhost --port 9443 --cert-file certs/client.crt --key-file keys/client.key --ca-cert-file certs/ca.crt
|
73
|
+
|
74
|
+
# HTTPS with custom SSL settings
|
75
|
+
python embed_client/example_async_usage.py --base-url https://localhost --port 9443 --ssl-verify-mode CERT_REQUIRED --ssl-check-hostname --ssl-check-expiry
|
76
|
+
|
77
|
+
CONFIGURATION EXAMPLES:
|
78
|
+
# Using configuration file
|
79
|
+
python embed_client/example_async_usage.py --config configs/https_token.json
|
80
|
+
|
81
|
+
# Using environment variables
|
82
|
+
export EMBED_CLIENT_BASE_URL=https://secure.example.com
|
83
|
+
export EMBED_CLIENT_PORT=9443
|
84
|
+
export EMBED_CLIENT_AUTH_METHOD=api_key
|
85
|
+
export EMBED_CLIENT_API_KEY=production_key
|
24
86
|
python embed_client/example_async_usage.py
|
25
87
|
|
26
|
-
|
88
|
+
DEMO MODE:
|
89
|
+
# Show all security modes demonstration
|
90
|
+
python embed_client/example_async_usage.py --demo-mode
|
91
|
+
|
92
|
+
PROGRAMMATIC USAGE EXAMPLES:
|
27
93
|
import asyncio
|
28
94
|
from embed_client.async_client import EmbeddingServiceAsyncClient
|
95
|
+
from embed_client.config import ClientConfig
|
96
|
+
from embed_client.client_factory import ClientFactory, create_client
|
97
|
+
|
29
98
|
async def main():
|
30
|
-
|
31
|
-
|
32
|
-
await client.close()
|
99
|
+
# Method 1: Direct client creation
|
100
|
+
client = EmbeddingServiceAsyncClient('http://localhost', 8001)
|
101
|
+
await client.close()
|
102
|
+
|
103
|
+
# Method 2: Using configuration
|
104
|
+
config = ClientConfig()
|
105
|
+
config.configure_server('http://localhost', 8001)
|
106
|
+
client = EmbeddingServiceAsyncClient.from_config(config)
|
107
|
+
await client.close()
|
108
|
+
|
109
|
+
# Method 3: Using factory with automatic detection
|
110
|
+
client = create_client('https://localhost', 9443, auth_method='api_key', api_key='key')
|
111
|
+
await client.close()
|
112
|
+
|
113
|
+
# Method 4: Using specific factory method
|
114
|
+
client = ClientFactory.create_https_token_client(
|
115
|
+
'https://localhost', 9443, 'api_key', api_key='key'
|
116
|
+
)
|
117
|
+
await client.close()
|
118
|
+
|
119
|
+
# Method 5: Using with_auth method for dynamic authentication
|
120
|
+
client = EmbeddingServiceAsyncClient('http://localhost', 8001)
|
121
|
+
client = client.with_auth('api_key', api_key='dynamic_key')
|
122
|
+
await client.close()
|
123
|
+
|
33
124
|
asyncio.run(main())
|
34
125
|
"""
|
35
126
|
|
127
|
+
import argparse
|
36
128
|
import asyncio
|
37
|
-
import
|
129
|
+
import json
|
38
130
|
import os
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
EmbeddingServiceConfigError
|
131
|
+
import sys
|
132
|
+
from typing import Dict, Any, Optional, Union
|
133
|
+
|
134
|
+
from embed_client.async_client import EmbeddingServiceAsyncClient, EmbeddingServiceError, EmbeddingServiceConfigError
|
135
|
+
from embed_client.config import ClientConfig
|
136
|
+
from embed_client.client_factory import (
|
137
|
+
ClientFactory, SecurityMode, create_client, create_client_from_config,
|
138
|
+
create_client_from_env, detect_security_mode
|
48
139
|
)
|
49
140
|
|
141
|
+
|
50
142
|
def get_params():
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
143
|
+
"""Parse command line arguments and environment variables for client configuration."""
|
144
|
+
parser = argparse.ArgumentParser(description="Embedding Service Async Client Example - All Security Modes")
|
145
|
+
|
146
|
+
# Basic connection parameters
|
147
|
+
parser.add_argument("--base-url", "-b", help="Base URL of the embedding service")
|
148
|
+
parser.add_argument("--port", "-p", type=int, help="Port of the embedding service")
|
149
|
+
parser.add_argument("--config", "-c", help="Path to configuration file")
|
150
|
+
|
151
|
+
# Client factory mode
|
152
|
+
parser.add_argument("--factory-mode", choices=["auto", "http", "http_token", "https", "https_token", "mtls", "mtls_roles"],
|
153
|
+
default="auto", help="Client factory mode (auto for automatic detection)")
|
154
|
+
|
155
|
+
# Authentication parameters
|
156
|
+
parser.add_argument("--auth-method", choices=["none", "api_key", "jwt", "basic", "certificate"],
|
157
|
+
default="none", help="Authentication method")
|
158
|
+
parser.add_argument("--api-key", help="API key for api_key authentication")
|
159
|
+
parser.add_argument("--jwt-secret", help="JWT secret for jwt authentication")
|
160
|
+
parser.add_argument("--jwt-username", help="JWT username for jwt authentication")
|
161
|
+
parser.add_argument("--jwt-password", help="JWT password for jwt authentication")
|
162
|
+
parser.add_argument("--username", help="Username for basic authentication")
|
163
|
+
parser.add_argument("--password", help="Password for basic authentication")
|
164
|
+
parser.add_argument("--cert-file", help="Certificate file for certificate authentication")
|
165
|
+
parser.add_argument("--key-file", help="Key file for certificate authentication")
|
166
|
+
|
167
|
+
# SSL/TLS parameters
|
168
|
+
parser.add_argument("--ssl-verify-mode", choices=["CERT_NONE", "CERT_OPTIONAL", "CERT_REQUIRED"],
|
169
|
+
default="CERT_REQUIRED", help="SSL certificate verification mode")
|
170
|
+
parser.add_argument("--ssl-check-hostname", action="store_true", default=True,
|
171
|
+
help="Enable SSL hostname checking")
|
172
|
+
parser.add_argument("--ssl-check-expiry", action="store_true", default=True,
|
173
|
+
help="Enable SSL certificate expiry checking")
|
174
|
+
parser.add_argument("--ca-cert-file", help="CA certificate file for SSL verification")
|
175
|
+
|
176
|
+
# Role-based access control (for mTLS + Roles)
|
177
|
+
parser.add_argument("--roles", help="Comma-separated list of roles for mTLS + Roles mode")
|
178
|
+
parser.add_argument("--role-attributes", help="JSON string of role attributes for mTLS + Roles mode")
|
179
|
+
|
180
|
+
# Additional parameters
|
181
|
+
parser.add_argument("--timeout", type=float, default=30.0, help="Request timeout in seconds")
|
182
|
+
parser.add_argument("--demo-mode", action="store_true", help="Run in demo mode (show all security modes)")
|
183
|
+
|
184
|
+
args = parser.parse_args()
|
185
|
+
|
186
|
+
# Store demo_mode in args for later use
|
187
|
+
args.demo_mode = args.demo_mode
|
188
|
+
|
189
|
+
# If demo mode is requested, return args directly
|
190
|
+
if args.demo_mode:
|
191
|
+
return args
|
192
|
+
|
193
|
+
# If config file is provided, load it
|
194
|
+
if args.config:
|
195
|
+
try:
|
196
|
+
config = ClientConfig()
|
197
|
+
config.load_from_file(args.config)
|
198
|
+
return config
|
199
|
+
except Exception as e:
|
200
|
+
print(f"Error loading config file {args.config}: {e}")
|
201
|
+
sys.exit(1)
|
202
|
+
|
203
|
+
# Otherwise, build config from arguments and environment variables
|
204
|
+
base_url = args.base_url or os.environ.get("EMBED_CLIENT_BASE_URL", "http://localhost")
|
205
|
+
port = args.port or int(os.environ.get("EMBED_CLIENT_PORT", "8001"))
|
206
|
+
|
62
207
|
if not base_url or not port:
|
63
208
|
print("Error: base_url and port must be provided via --base-url/--port arguments or EMBED_CLIENT_BASE_URL/EMBED_CLIENT_PORT environment variables.")
|
64
209
|
sys.exit(1)
|
65
|
-
|
66
|
-
|
210
|
+
|
211
|
+
# Build configuration dictionary
|
212
|
+
config_dict = {
|
213
|
+
"server": {
|
214
|
+
"host": base_url,
|
215
|
+
"port": port
|
216
|
+
},
|
217
|
+
"client": {
|
218
|
+
"timeout": args.timeout
|
219
|
+
},
|
220
|
+
"auth": {
|
221
|
+
"method": args.auth_method
|
222
|
+
}
|
223
|
+
}
|
224
|
+
|
225
|
+
# Add authentication configuration
|
226
|
+
if args.auth_method == "api_key":
|
227
|
+
api_key = args.api_key or os.environ.get("EMBED_CLIENT_API_KEY")
|
228
|
+
if api_key:
|
229
|
+
config_dict["auth"]["api_keys"] = {"user": api_key}
|
230
|
+
else:
|
231
|
+
print("Warning: API key not provided for api_key authentication")
|
232
|
+
|
233
|
+
elif args.auth_method == "jwt":
|
234
|
+
jwt_secret = args.jwt_secret or os.environ.get("EMBED_CLIENT_JWT_SECRET")
|
235
|
+
jwt_username = args.jwt_username or os.environ.get("EMBED_CLIENT_JWT_USERNAME")
|
236
|
+
jwt_password = args.jwt_password or os.environ.get("EMBED_CLIENT_JWT_PASSWORD")
|
237
|
+
|
238
|
+
if jwt_secret and jwt_username and jwt_password:
|
239
|
+
config_dict["auth"]["jwt"] = {
|
240
|
+
"secret": jwt_secret,
|
241
|
+
"username": jwt_username,
|
242
|
+
"password": jwt_password
|
243
|
+
}
|
244
|
+
else:
|
245
|
+
print("Warning: JWT credentials not fully provided")
|
246
|
+
|
247
|
+
elif args.auth_method == "basic":
|
248
|
+
username = args.username or os.environ.get("EMBED_CLIENT_USERNAME")
|
249
|
+
password = args.password or os.environ.get("EMBED_CLIENT_PASSWORD")
|
250
|
+
|
251
|
+
if username and password:
|
252
|
+
config_dict["auth"]["basic"] = {
|
253
|
+
"username": username,
|
254
|
+
"password": password
|
255
|
+
}
|
256
|
+
else:
|
257
|
+
print("Warning: Basic auth credentials not fully provided")
|
258
|
+
|
259
|
+
elif args.auth_method == "certificate":
|
260
|
+
cert_file = args.cert_file or os.environ.get("EMBED_CLIENT_CERT_FILE")
|
261
|
+
key_file = args.key_file or os.environ.get("EMBED_CLIENT_KEY_FILE")
|
262
|
+
|
263
|
+
if cert_file and key_file:
|
264
|
+
config_dict["auth"]["certificate"] = {
|
265
|
+
"cert_file": cert_file,
|
266
|
+
"key_file": key_file
|
267
|
+
}
|
268
|
+
else:
|
269
|
+
print("Warning: Certificate files not fully provided")
|
270
|
+
|
271
|
+
# Add SSL configuration if HTTPS is used or SSL parameters are provided
|
272
|
+
if base_url.startswith("https://") or args.ssl_verify_mode != "CERT_REQUIRED" or args.ca_cert_file:
|
273
|
+
# Force check_hostname=False for CERT_NONE mode
|
274
|
+
check_hostname = args.ssl_check_hostname
|
275
|
+
if args.ssl_verify_mode == "CERT_NONE":
|
276
|
+
check_hostname = False
|
277
|
+
|
278
|
+
config_dict["ssl"] = {
|
279
|
+
"enabled": True,
|
280
|
+
"verify_mode": args.ssl_verify_mode,
|
281
|
+
"check_hostname": check_hostname,
|
282
|
+
"check_expiry": args.ssl_check_expiry
|
283
|
+
}
|
284
|
+
|
285
|
+
if args.ca_cert_file:
|
286
|
+
config_dict["ssl"]["ca_cert_file"] = args.ca_cert_file
|
287
|
+
|
288
|
+
# Add client certificates for mTLS
|
289
|
+
if args.cert_file:
|
290
|
+
config_dict["ssl"]["cert_file"] = args.cert_file
|
291
|
+
if args.key_file:
|
292
|
+
config_dict["ssl"]["key_file"] = args.key_file
|
293
|
+
|
294
|
+
# Add role-based access control for mTLS + Roles
|
295
|
+
if args.roles:
|
296
|
+
roles = [role.strip() for role in args.roles.split(",")]
|
297
|
+
config_dict["roles"] = roles
|
298
|
+
|
299
|
+
if args.role_attributes:
|
300
|
+
try:
|
301
|
+
role_attributes = json.loads(args.role_attributes)
|
302
|
+
config_dict["role_attributes"] = role_attributes
|
303
|
+
except json.JSONDecodeError:
|
304
|
+
print("Warning: Invalid JSON in role_attributes")
|
305
|
+
|
306
|
+
return config_dict
|
67
307
|
|
68
|
-
|
308
|
+
|
309
|
+
def extract_embeddings(result):
|
69
310
|
"""Extract embeddings from the API response, supporting both old and new formats."""
|
70
311
|
# Handle direct embeddings field (old format compatibility)
|
71
312
|
if "embeddings" in result:
|
@@ -100,59 +341,306 @@ def extract_vectors(result):
|
|
100
341
|
|
101
342
|
raise ValueError(f"Cannot extract embeddings from response: {result}")
|
102
343
|
|
344
|
+
|
345
|
+
async def run_client_examples(client):
|
346
|
+
"""Run example operations with the client."""
|
347
|
+
# Check health
|
348
|
+
try:
|
349
|
+
health = await client.health()
|
350
|
+
print("Service health:", health)
|
351
|
+
except EmbeddingServiceError as e:
|
352
|
+
print(f"Error during health check: {e}")
|
353
|
+
return
|
354
|
+
|
355
|
+
# Get OpenAPI schema
|
356
|
+
try:
|
357
|
+
schema = await client.get_openapi_schema()
|
358
|
+
print(f"OpenAPI schema version: {schema.get('info', {}).get('version', 'unknown')}")
|
359
|
+
except EmbeddingServiceError as e:
|
360
|
+
print(f"Error getting OpenAPI schema: {e}")
|
361
|
+
|
362
|
+
# Get available commands
|
363
|
+
try:
|
364
|
+
commands = await client.get_commands()
|
365
|
+
print(f"Available commands: {commands}")
|
366
|
+
except EmbeddingServiceError as e:
|
367
|
+
print(f"Error getting commands: {e}")
|
368
|
+
|
369
|
+
# Test embedding generation
|
370
|
+
try:
|
371
|
+
texts = ["Hello, world!", "This is a test sentence.", "Embedding service is working!"]
|
372
|
+
result = await client.cmd("embed", {"texts": texts})
|
373
|
+
|
374
|
+
if result.get("success"):
|
375
|
+
embeddings = extract_embeddings(result)
|
376
|
+
print(f"Generated {len(embeddings)} embeddings")
|
377
|
+
print(f"First embedding dimension: {len(embeddings[0]) if embeddings else 0}")
|
378
|
+
else:
|
379
|
+
print(f"Embedding generation failed: {result.get('error', 'Unknown error')}")
|
380
|
+
except EmbeddingServiceError as e:
|
381
|
+
print(f"Error during embedding generation: {e}")
|
382
|
+
|
383
|
+
|
384
|
+
async def demonstrate_security_modes():
|
385
|
+
"""Demonstrate all security modes using ClientFactory."""
|
386
|
+
print("=== Security Modes Demonstration ===")
|
387
|
+
print("This demonstration shows how to create clients for all 6 security modes.")
|
388
|
+
print("Note: These examples create client configurations but don't connect to actual servers.")
|
389
|
+
|
390
|
+
# 1. HTTP mode
|
391
|
+
print("\n1. HTTP Mode (no authentication, no SSL):")
|
392
|
+
print(" Use case: Development, internal networks, trusted environments")
|
393
|
+
try:
|
394
|
+
client = ClientFactory.create_http_client("http://localhost", 8001)
|
395
|
+
print(f" ✓ Created HTTP client: {client.base_url}:{client.port}")
|
396
|
+
print(f" ✓ SSL enabled: {client.is_ssl_enabled()}")
|
397
|
+
print(f" ✓ Authenticated: {client.is_authenticated()}")
|
398
|
+
print(f" ✓ Auth method: {client.get_auth_method()}")
|
399
|
+
await client.close()
|
400
|
+
except Exception as e:
|
401
|
+
print(f" ✗ Error: {e}")
|
402
|
+
|
403
|
+
# 2. HTTP + Token mode
|
404
|
+
print("\n2. HTTP + Token Mode (HTTP with API key):")
|
405
|
+
print(" Use case: API access control, simple authentication")
|
406
|
+
try:
|
407
|
+
client = ClientFactory.create_http_token_client(
|
408
|
+
"http://localhost", 8001, "api_key", api_key="demo_key"
|
409
|
+
)
|
410
|
+
print(f" ✓ Created HTTP + Token client: {client.base_url}:{client.port}")
|
411
|
+
print(f" ✓ SSL enabled: {client.is_ssl_enabled()}")
|
412
|
+
print(f" ✓ Authenticated: {client.is_authenticated()}")
|
413
|
+
print(f" ✓ Auth method: {client.get_auth_method()}")
|
414
|
+
if client.is_authenticated():
|
415
|
+
headers = client.get_auth_headers()
|
416
|
+
print(f" ✓ Auth headers: {headers}")
|
417
|
+
await client.close()
|
418
|
+
except Exception as e:
|
419
|
+
print(f" ✗ Error: {e}")
|
420
|
+
|
421
|
+
# 3. HTTPS mode
|
422
|
+
print("\n3. HTTPS Mode (HTTPS with server certificates):")
|
423
|
+
print(" Use case: Secure communication, public networks")
|
424
|
+
try:
|
425
|
+
client = ClientFactory.create_https_client("https://localhost", 9443)
|
426
|
+
print(f" ✓ Created HTTPS client: {client.base_url}:{client.port}")
|
427
|
+
print(f" ✓ SSL enabled: {client.is_ssl_enabled()}")
|
428
|
+
print(f" ✓ Authenticated: {client.is_authenticated()}")
|
429
|
+
if client.is_ssl_enabled():
|
430
|
+
ssl_config = client.get_ssl_config()
|
431
|
+
print(f" ✓ SSL config: {ssl_config}")
|
432
|
+
protocols = client.get_supported_ssl_protocols()
|
433
|
+
print(f" ✓ Supported SSL protocols: {protocols}")
|
434
|
+
await client.close()
|
435
|
+
except Exception as e:
|
436
|
+
print(f" ✗ Error: {e}")
|
437
|
+
|
438
|
+
# 4. HTTPS + Token mode
|
439
|
+
print("\n4. HTTPS + Token Mode (HTTPS with server certificates + authentication):")
|
440
|
+
print(" Use case: Secure API access, production environments")
|
441
|
+
try:
|
442
|
+
client = ClientFactory.create_https_token_client(
|
443
|
+
"https://localhost", 9443, "basic", username="admin", password="secret"
|
444
|
+
)
|
445
|
+
print(f" ✓ Created HTTPS + Token client: {client.base_url}:{client.port}")
|
446
|
+
print(f" ✓ SSL enabled: {client.is_ssl_enabled()}")
|
447
|
+
print(f" ✓ Authenticated: {client.is_authenticated()}")
|
448
|
+
print(f" ✓ Auth method: {client.get_auth_method()}")
|
449
|
+
if client.is_authenticated():
|
450
|
+
headers = client.get_auth_headers()
|
451
|
+
print(f" ✓ Auth headers: {headers}")
|
452
|
+
await client.close()
|
453
|
+
except Exception as e:
|
454
|
+
print(f" ✗ Error: {e}")
|
455
|
+
|
456
|
+
# 5. mTLS mode
|
457
|
+
print("\n5. mTLS Mode (mutual TLS with client and server certificates):")
|
458
|
+
print(" Use case: High security, client certificate authentication")
|
459
|
+
try:
|
460
|
+
client = ClientFactory.create_mtls_client(
|
461
|
+
"https://localhost", "client_cert.pem", "client_key.pem", 9443
|
462
|
+
)
|
463
|
+
print(f" ✓ Created mTLS client: {client.base_url}:{client.port}")
|
464
|
+
print(f" ✓ SSL enabled: {client.is_ssl_enabled()}")
|
465
|
+
print(f" ✓ mTLS enabled: {client.is_mtls_enabled()}")
|
466
|
+
print(f" ✓ Authenticated: {client.is_authenticated()}")
|
467
|
+
if client.is_ssl_enabled():
|
468
|
+
ssl_config = client.get_ssl_config()
|
469
|
+
print(f" ✓ SSL config: {ssl_config}")
|
470
|
+
await client.close()
|
471
|
+
except Exception as e:
|
472
|
+
print(f" ✗ Error: {e}")
|
473
|
+
|
474
|
+
# 6. mTLS + Roles mode
|
475
|
+
print("\n6. mTLS + Roles Mode (mTLS with role-based access control):")
|
476
|
+
print(" Use case: Enterprise security, role-based permissions")
|
477
|
+
try:
|
478
|
+
client = ClientFactory.create_mtls_roles_client(
|
479
|
+
"https://localhost", "client_cert.pem", "client_key.pem", 9443,
|
480
|
+
roles=["admin", "user"], role_attributes={"department": "IT"}
|
481
|
+
)
|
482
|
+
print(f" ✓ Created mTLS + Roles client: {client.base_url}:{client.port}")
|
483
|
+
print(f" ✓ SSL enabled: {client.is_ssl_enabled()}")
|
484
|
+
print(f" ✓ mTLS enabled: {client.is_mtls_enabled()}")
|
485
|
+
print(f" ✓ Authenticated: {client.is_authenticated()}")
|
486
|
+
if client.is_authenticated():
|
487
|
+
headers = client.get_auth_headers()
|
488
|
+
print(f" ✓ Auth headers: {headers}")
|
489
|
+
await client.close()
|
490
|
+
except Exception as e:
|
491
|
+
print(f" ✗ Error: {e}")
|
492
|
+
|
493
|
+
print("\n=== Security Mode Summary ===")
|
494
|
+
print("1. HTTP: Basic connectivity, no security")
|
495
|
+
print("2. HTTP + Token: API key authentication over HTTP")
|
496
|
+
print("3. HTTPS: Encrypted communication with server certificates")
|
497
|
+
print("4. HTTPS + Token: Encrypted communication + authentication")
|
498
|
+
print("5. mTLS: Mutual certificate authentication")
|
499
|
+
print("6. mTLS + Roles: Mutual certificates + role-based access control")
|
500
|
+
|
501
|
+
|
502
|
+
async def demonstrate_automatic_detection():
|
503
|
+
"""Demonstrate automatic security mode detection."""
|
504
|
+
print("\n=== Automatic Security Mode Detection ===")
|
505
|
+
print("This shows how the client automatically detects the appropriate security mode.")
|
506
|
+
|
507
|
+
test_cases = [
|
508
|
+
("http://localhost", None, None, None, None, "HTTP"),
|
509
|
+
("http://localhost", "api_key", None, None, None, "HTTP + Token"),
|
510
|
+
("https://localhost", None, None, None, None, "HTTPS"),
|
511
|
+
("https://localhost", "api_key", None, None, None, "HTTPS + Token"),
|
512
|
+
("https://localhost", None, None, "cert.pem", "key.pem", "mTLS"),
|
513
|
+
("https://localhost", None, None, "cert.pem", "key.pem", "mTLS + Roles", {"roles": ["admin"]}),
|
514
|
+
]
|
515
|
+
|
516
|
+
for case in test_cases:
|
517
|
+
if len(case) == 6:
|
518
|
+
base_url, auth_method, ssl_enabled, cert_file, key_file, expected = case
|
519
|
+
kwargs = {}
|
520
|
+
else:
|
521
|
+
base_url, auth_method, ssl_enabled, cert_file, key_file, expected, kwargs = case
|
522
|
+
|
523
|
+
try:
|
524
|
+
mode = detect_security_mode(base_url, auth_method, ssl_enabled, cert_file, key_file, **kwargs)
|
525
|
+
print(f" ✓ {base_url} + {auth_method or 'none'} + {cert_file or 'no cert'} -> {mode} ({expected})")
|
526
|
+
except Exception as e:
|
527
|
+
print(f" ✗ Error detecting mode for {base_url}: {e}")
|
528
|
+
|
529
|
+
|
530
|
+
async def demonstrate_with_auth_method():
|
531
|
+
"""Demonstrate the with_auth method for dynamic authentication."""
|
532
|
+
print("\n=== Dynamic Authentication with with_auth() Method ===")
|
533
|
+
print("This shows how to create clients with different authentication methods using the with_auth class method.")
|
534
|
+
|
535
|
+
# Demonstrate different authentication methods
|
536
|
+
auth_examples = [
|
537
|
+
("api_key", {"api_key": "dynamic_api_key"}, "API Key Authentication"),
|
538
|
+
("jwt", {"secret": "secret", "username": "user", "password": "pass"}, "JWT Authentication"),
|
539
|
+
("basic", {"username": "admin", "password": "secret"}, "Basic Authentication"),
|
540
|
+
("certificate", {"cert_file": "client.crt", "key_file": "client.key"}, "Certificate Authentication"),
|
541
|
+
]
|
542
|
+
|
543
|
+
for auth_method, kwargs, description in auth_examples:
|
544
|
+
try:
|
545
|
+
print(f"\n{description}:")
|
546
|
+
auth_client = EmbeddingServiceAsyncClient.with_auth("http://localhost", 8001, auth_method, **kwargs)
|
547
|
+
print(f" ✓ Auth method: {auth_client.get_auth_method()}")
|
548
|
+
print(f" ✓ Authenticated: {auth_client.is_authenticated()}")
|
549
|
+
if auth_client.is_authenticated():
|
550
|
+
headers = auth_client.get_auth_headers()
|
551
|
+
print(f" ✓ Auth headers: {headers}")
|
552
|
+
await auth_client.close()
|
553
|
+
except Exception as e:
|
554
|
+
print(f" ✗ Error with {auth_method}: {e}")
|
555
|
+
|
556
|
+
print("\n✓ Dynamic authentication demonstration completed.")
|
557
|
+
|
558
|
+
|
103
559
|
async def main():
|
104
560
|
try:
|
105
|
-
|
561
|
+
config = get_params()
|
562
|
+
|
563
|
+
# Check if demo mode is requested
|
564
|
+
if hasattr(config, 'demo_mode') and config.demo_mode:
|
565
|
+
await demonstrate_security_modes()
|
566
|
+
await demonstrate_automatic_detection()
|
567
|
+
await demonstrate_with_auth_method()
|
568
|
+
return
|
569
|
+
|
570
|
+
# Create client based on factory mode
|
571
|
+
if isinstance(config, ClientConfig):
|
572
|
+
# Using configuration object
|
573
|
+
client = EmbeddingServiceAsyncClient.from_config(config)
|
574
|
+
else:
|
575
|
+
# Using configuration dictionary
|
576
|
+
factory_mode = getattr(config, 'factory_mode', 'auto')
|
577
|
+
|
578
|
+
if factory_mode == "auto":
|
579
|
+
# Automatic detection
|
580
|
+
client = create_client(
|
581
|
+
config["server"]["host"],
|
582
|
+
config["server"]["port"],
|
583
|
+
auth_method=config["auth"]["method"],
|
584
|
+
**{k: v for k, v in config.items() if k not in ["server", "auth", "ssl", "client"]}
|
585
|
+
)
|
586
|
+
else:
|
587
|
+
# Specific factory method
|
588
|
+
base_url = config["server"]["host"]
|
589
|
+
port = config["server"]["port"]
|
590
|
+
auth_method = config["auth"]["method"]
|
591
|
+
|
592
|
+
if factory_mode == "http":
|
593
|
+
client = ClientFactory.create_http_client(base_url, port)
|
594
|
+
elif factory_mode == "http_token":
|
595
|
+
client = ClientFactory.create_http_token_client(base_url, port, auth_method, **config.get("auth", {}))
|
596
|
+
elif factory_mode == "https":
|
597
|
+
client = ClientFactory.create_https_client(base_url, port)
|
598
|
+
elif factory_mode == "https_token":
|
599
|
+
client = ClientFactory.create_https_token_client(base_url, port, auth_method, **config.get("auth", {}))
|
600
|
+
elif factory_mode == "mtls":
|
601
|
+
cert_file = config.get("ssl", {}).get("cert_file", "client_cert.pem")
|
602
|
+
key_file = config.get("ssl", {}).get("key_file", "client_key.pem")
|
603
|
+
client = ClientFactory.create_mtls_client(base_url, cert_file, key_file, port)
|
604
|
+
elif factory_mode == "mtls_roles":
|
605
|
+
cert_file = config.get("ssl", {}).get("cert_file", "client_cert.pem")
|
606
|
+
key_file = config.get("ssl", {}).get("key_file", "client_key.pem")
|
607
|
+
roles = config.get("roles", ["admin"])
|
608
|
+
role_attributes = config.get("role_attributes", {})
|
609
|
+
client = ClientFactory.create_mtls_roles_client(
|
610
|
+
base_url, cert_file, key_file, port, roles, role_attributes
|
611
|
+
)
|
612
|
+
else:
|
613
|
+
client = EmbeddingServiceAsyncClient(config_dict=config)
|
614
|
+
|
615
|
+
print(f"Client configuration:")
|
616
|
+
print(f" Base URL: {client.base_url}")
|
617
|
+
print(f" Port: {client.port}")
|
618
|
+
print(f" Authentication: {client.get_auth_method()}")
|
619
|
+
print(f" Authenticated: {client.is_authenticated()}")
|
620
|
+
if client.is_authenticated():
|
621
|
+
headers = client.get_auth_headers()
|
622
|
+
print(f" Auth headers: {headers}")
|
623
|
+
print(f" SSL enabled: {client.is_ssl_enabled()}")
|
624
|
+
print(f" mTLS enabled: {client.is_mtls_enabled()}")
|
625
|
+
if client.is_ssl_enabled():
|
626
|
+
ssl_config = client.get_ssl_config()
|
627
|
+
print(f" SSL config: {ssl_config}")
|
628
|
+
protocols = client.get_supported_ssl_protocols()
|
629
|
+
print(f" Supported SSL protocols: {protocols}")
|
630
|
+
print()
|
631
|
+
|
106
632
|
# Explicit open/close example
|
107
|
-
client = EmbeddingServiceAsyncClient(base_url=base_url, port=port)
|
108
633
|
print("Explicit session open/close example:")
|
109
634
|
await client.close()
|
110
635
|
print("Session closed explicitly (manual close example).\n")
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
except EmbeddingServiceTimeoutError as e:
|
120
|
-
print(f"Timeout error during health check: {e}")
|
121
|
-
except EmbeddingServiceError as e:
|
122
|
-
print(f"Error during health check: {e}")
|
123
|
-
|
124
|
-
# Request embeddings for a list of texts
|
125
|
-
texts = ["hello world", "test embedding"]
|
126
|
-
try:
|
127
|
-
result = await client.cmd("embed", params={"texts": texts})
|
128
|
-
vectors = extract_vectors(result)
|
129
|
-
print(f"Embeddings for {len(texts)} texts:")
|
130
|
-
for i, vec in enumerate(vectors):
|
131
|
-
print(f" Text: {texts[i]!r}\n Vector: {vec[:5]}... (total {len(vec)} dims)")
|
132
|
-
except EmbeddingServiceAPIError as e:
|
133
|
-
print(f"API error during embedding: {e}")
|
134
|
-
except EmbeddingServiceConnectionError as e:
|
135
|
-
print(f"Connection error during embedding: {e}")
|
136
|
-
except EmbeddingServiceTimeoutError as e:
|
137
|
-
print(f"Timeout error during embedding: {e}")
|
138
|
-
except EmbeddingServiceError as e:
|
139
|
-
print(f"Error during embedding: {e}")
|
140
|
-
|
141
|
-
# Example: health check via cmd
|
142
|
-
try:
|
143
|
-
result = await client.cmd("health")
|
144
|
-
print("Health check result:", result)
|
145
|
-
except EmbeddingServiceError as e:
|
146
|
-
print(f"Error during health command: {e}")
|
147
|
-
|
148
|
-
# Example: error handling for empty command
|
149
|
-
try:
|
150
|
-
result = await client.cmd("")
|
151
|
-
print("Empty command result:", result)
|
152
|
-
except EmbeddingServiceAPIError as e:
|
153
|
-
print(f"Expected error for empty command: {e}")
|
154
|
-
except EmbeddingServiceError as e:
|
155
|
-
print(f"Error for empty command: {e}")
|
636
|
+
|
637
|
+
# Use context manager
|
638
|
+
if isinstance(config, ClientConfig):
|
639
|
+
async with EmbeddingServiceAsyncClient.from_config(config) as client:
|
640
|
+
await run_client_examples(client)
|
641
|
+
else:
|
642
|
+
async with EmbeddingServiceAsyncClient(config_dict=config) as client:
|
643
|
+
await run_client_examples(client)
|
156
644
|
|
157
645
|
except EmbeddingServiceConfigError as e:
|
158
646
|
print(f"Configuration error: {e}")
|
@@ -162,4 +650,4 @@ async def main():
|
|
162
650
|
sys.exit(1)
|
163
651
|
|
164
652
|
if __name__ == "__main__":
|
165
|
-
asyncio.run(main())
|
653
|
+
asyncio.run(main())
|