dataapp-resource-proxy 0.1.0__tar.gz
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.
- dataapp_resource_proxy-0.1.0/PKG-INFO +6 -0
- dataapp_resource_proxy-0.1.0/README.md +273 -0
- dataapp_resource_proxy-0.1.0/local-resource.env.example +22 -0
- dataapp_resource_proxy-0.1.0/pyproject.toml +33 -0
- dataapp_resource_proxy-0.1.0/src/dataapp_resource_proxy/__init__.py +15 -0
- dataapp_resource_proxy-0.1.0/src/dataapp_resource_proxy/__main__.py +65 -0
- dataapp_resource_proxy-0.1.0/src/dataapp_resource_proxy/_local_config.py +286 -0
- dataapp_resource_proxy-0.1.0/src/dataapp_resource_proxy/client.py +1813 -0
- dataapp_resource_proxy-0.1.0/src/dataapp_resource_proxy/errors.py +16 -0
- dataapp_resource_proxy-0.1.0/src/dataapp_resource_proxy/handles.py +199 -0
- dataapp_resource_proxy-0.1.0/src/dataapp_resource_proxy/py.typed +0 -0
- dataapp_resource_proxy-0.1.0/tests/test_captcha_directory.py +163 -0
- dataapp_resource_proxy-0.1.0/tests/test_client.py +743 -0
- dataapp_resource_proxy-0.1.0/tests/test_local_config.py +361 -0
- dataapp_resource_proxy-0.1.0/tests/test_project_environment.py +187 -0
- dataapp_resource_proxy-0.1.0/tests/test_proxy_catalog.py +192 -0
- dataapp_resource_proxy-0.1.0/tests/test_regional_client.py +673 -0
- dataapp_resource_proxy-0.1.0/uv.lock +468 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# DataApp Resource Proxy client
|
|
2
|
+
|
|
3
|
+
This package acquires run-scoped DataOS browser and proxy resources. It does not
|
|
4
|
+
contain supplier credentials, crawler code, or server components.
|
|
5
|
+
|
|
6
|
+
The local candidate supports `captcha_types(type=..., refresh=True)` and generic
|
|
7
|
+
`solve_captcha(type=..., task_variant=..., parameters=...)`. Query the directory
|
|
8
|
+
before selecting new variants. The developer directory only returns variants
|
|
9
|
+
whose Billing classifications have effective supplier-cost quotes. Its
|
|
10
|
+
`pricing_version` identifies the price snapshot used for that decision, and
|
|
11
|
+
`available_billing_types` lists the enabled classifications without exposing
|
|
12
|
+
supplier prices. Queries do not submit solver tasks; explicit solves are
|
|
13
|
+
metered. Structured answers are available through `CaptchaTask.data`.
|
|
14
|
+
See [the RP task-directory contract](../../docs/resources/captcha-directory.md).
|
|
15
|
+
These fields require matching service/Runtime bridge versions; updating this
|
|
16
|
+
client alone does not upgrade a deployed platform.
|
|
17
|
+
|
|
18
|
+
CAPTCHA directory results use the same short client cache as other resource
|
|
19
|
+
catalogs. Pass `refresh=True` when the UI needs current availability. The
|
|
20
|
+
directory is advisory: Resource Proxy performs the authoritative check again at
|
|
21
|
+
submission, so manually supplied or stale parameters cannot enable an unpriced
|
|
22
|
+
task. Older directory responses without availability metadata are rejected
|
|
23
|
+
instead of being treated as unrestricted support.
|
|
24
|
+
|
|
25
|
+
The current development line supports account-environment routing, regional
|
|
26
|
+
resource receipts, and the `DEFERRED` resource-cost receipt contract.
|
|
27
|
+
|
|
28
|
+
For local development against pre, only the developer's ordinary API Key is
|
|
29
|
+
required. The client defaults to the `bazhuayu_pre` account, uses the verified
|
|
30
|
+
domestic and overseas pre entries, and selects the resource node independently
|
|
31
|
+
from the account and Billing environment.
|
|
32
|
+
|
|
33
|
+
Managed proxies and CAPTCHA solves accrue resource costs. After the developer
|
|
34
|
+
confirms that the local test may use these services, run the masked setup:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
python -m dataapp_resource_proxy configure
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The command reads the Key without displaying it and stores it outside the
|
|
41
|
+
project in a mode-`600` per-user file. Obtain the Key from **Account Center >
|
|
42
|
+
API Keys**: [pre](https://pre.bazhuayu.com/console/account-center/api-keys) for
|
|
43
|
+
the default pre setup, or
|
|
44
|
+
[production](https://www.bazhuayu.com/console/account-center/api-keys) for a
|
|
45
|
+
production account. Never paste a Key into chat or package it with an App.
|
|
46
|
+
Platform Runs use injected run identity and do not need a developer API Key.
|
|
47
|
+
When local code runs inside a container, the host's per-user file is not visible
|
|
48
|
+
automatically. Mount that one file read-only at the same path, or pass
|
|
49
|
+
`DATAAPP_API_KEY` through the container's secret/environment mechanism. Do not
|
|
50
|
+
copy the file into the image or build context.
|
|
51
|
+
|
|
52
|
+
Configure the application process with the following variables:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
DATAAPP_API_KEY=<developer-api-key>
|
|
56
|
+
DATAOS_RESOURCE_READ_TIMEOUT_SECONDS=10
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`DATAAPP_API_KEY` is the canonical process override. The deprecated
|
|
60
|
+
`DATAOS_API_KEY` remains a compatibility fallback; conflicting values are
|
|
61
|
+
rejected. The per-user setup file is loaded only for missing values, so an
|
|
62
|
+
explicit process value takes precedence. `DATAOS_APP_ID` remains optional
|
|
63
|
+
metadata and is not a prerequisite for local managed resources.
|
|
64
|
+
|
|
65
|
+
Regional `usages()` and `resource_charges()` reads use a 10-second per-node
|
|
66
|
+
deadline by default, so one slow node does not hide another node's result. Set
|
|
67
|
+
`DATAOS_RESOURCE_READ_TIMEOUT_SECONDS` to a finite value greater than 0 and at
|
|
68
|
+
most 30 seconds when a different local deadline is required. The
|
|
69
|
+
`regional_read_timeout` argument to `ResourceProxy.from_env()` takes precedence
|
|
70
|
+
over the environment value. Hosts can read the validated
|
|
71
|
+
`resources.regional_read_timeout` property when applying their own bounded
|
|
72
|
+
execution-shutdown guard.
|
|
73
|
+
|
|
74
|
+
The access profiles `bazhuayu_overseas_pre` and `bazhuayu_overseas` select an
|
|
75
|
+
overseas node while retaining the corresponding `bazhuayu_pre` or `bazhuayu`
|
|
76
|
+
account and Billing identity. They are routing profiles, not separate accounts.
|
|
77
|
+
`octoparse_pre` and `octoparse` remain distinct account environments for
|
|
78
|
+
compatibility. A node being reachable or healthy does not prove that identity
|
|
79
|
+
validation, supplier allocation, target-site access, or business-data
|
|
80
|
+
extraction will succeed.
|
|
81
|
+
|
|
82
|
+
The built-in pre endpoints are `https://pre-resource-proxy.bazhuayu.com:443`
|
|
83
|
+
for domestic resources and
|
|
84
|
+
`https://pre-resource-proxy-overseas.bazhuayu.com:443` for overseas resources.
|
|
85
|
+
Certificate and hostname verification stay enabled. Explicit URL variables below
|
|
86
|
+
can override these defaults for an isolated test or rollback.
|
|
87
|
+
|
|
88
|
+
Production profiles (`bazhuayu`, `bazhuayu_overseas`, and `octoparse`) have no built-in node
|
|
89
|
+
addresses until their public endpoints are verified. Configure one explicit
|
|
90
|
+
single-node URL:
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
DATAOS_RESOURCE_PROXY_URL=https://resource-proxy.example.com
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Or configure regional nodes independently:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
DATAOS_RESOURCE_PROXY_DOMESTIC_URL=https://domestic-resource-proxy.example.com
|
|
100
|
+
DATAOS_RESOURCE_PROXY_OVERSEAS_URL=https://overseas-resource-proxy.example.com
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Explicit URL variables override automatic pre-node selection. Supplying any
|
|
104
|
+
regional URL enables explicit regional mode, so an omitted region remains
|
|
105
|
+
unconfigured. This permits an overseas-only setup without routing domestic work
|
|
106
|
+
to the overseas node. `DATAOS_RESOURCE_PROXY_URL` keeps legacy single-node
|
|
107
|
+
semantics and is never supplemented with an automatic overseas node.
|
|
108
|
+
|
|
109
|
+
Then use the same resource API:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from dataapp_resource_proxy import ResourceProxy
|
|
113
|
+
|
|
114
|
+
async with ResourceProxy.from_env() as resources:
|
|
115
|
+
proxy = await resources.proxy(
|
|
116
|
+
country="US",
|
|
117
|
+
proxy_group="overseas_basic",
|
|
118
|
+
)
|
|
119
|
+
print(proxy.lease_id)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The API Key, returned proxy URL, and browser connection headers are secrets. Keep
|
|
123
|
+
them in local environment configuration; do not log, package, or store them in
|
|
124
|
+
application data. See `local-resource.env.example` for a value-free setup file.
|
|
125
|
+
|
|
126
|
+
New managed proxy requests accept `auto`, `domestic_basic`, `overseas_basic`,
|
|
127
|
+
or `overseas_enhanced`. `auto` uses the basic managed service. Supplier ordering
|
|
128
|
+
and location or duration support come from Resource Proxy's published catalog;
|
|
129
|
+
the client does not select suppliers. Existing handles may still report a legacy
|
|
130
|
+
group value from historical leases and remain readable.
|
|
131
|
+
|
|
132
|
+
Query the managed catalog before asking a user to choose a location. This is also
|
|
133
|
+
the preferred flow for an AI-generated DataApp:
|
|
134
|
+
|
|
135
|
+
Catalog methods require a node with the catalog API enabled. Older nodes can
|
|
136
|
+
still issue leases but return HTTP 404 for catalog queries. Report that capability
|
|
137
|
+
as unavailable; do not treat it as an empty geographic coverage list or silently
|
|
138
|
+
allocate a paid lease to discover coverage. A client package upgrade does not
|
|
139
|
+
upgrade the Resource Proxy server.
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
async with ResourceProxy.from_env() as resources:
|
|
143
|
+
groups = await resources.proxy_groups(network_preference="overseas")
|
|
144
|
+
countries = await resources.proxy_locations(
|
|
145
|
+
proxy_group="overseas_basic",
|
|
146
|
+
network_preference="overseas",
|
|
147
|
+
)
|
|
148
|
+
states = await resources.proxy_locations(
|
|
149
|
+
proxy_group="overseas_basic",
|
|
150
|
+
country="US",
|
|
151
|
+
)
|
|
152
|
+
if not states["items"]:
|
|
153
|
+
raise RuntimeError("No state coverage is currently listed; check the catalog status")
|
|
154
|
+
proxy = await resources.proxy(
|
|
155
|
+
proxy_group="overseas_basic",
|
|
156
|
+
country="US",
|
|
157
|
+
state=states["items"][0]["code"],
|
|
158
|
+
)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Catalog results describe configured geographic coverage. They are not a promise
|
|
162
|
+
of real-time supplier inventory, so a later lease request can still report that
|
|
163
|
+
a route is temporarily unavailable. `ResourceProxy.proxy_location_hints()`
|
|
164
|
+
returns a small non-authoritative list of popular countries for empty-state UI;
|
|
165
|
+
it never replaces a failed catalog query. Catalog queries use a 30-second,
|
|
166
|
+
per-client cache; pass `refresh=True` to bypass it.
|
|
167
|
+
|
|
168
|
+
For a locally developed Code App, `DATAOS_APP_ID` and `DATAOS_APP_VERSION` are
|
|
169
|
+
optional attribution metadata. The resource flow uses the ordinary platform
|
|
170
|
+
`DATAAPP_API_KEY`; it does not create a separate billing Key.
|
|
171
|
+
|
|
172
|
+
Inside a platform DataApp, obtain the same client from the Runtime so the
|
|
173
|
+
DataHub backend can bind requests to the current Run and Attempt without
|
|
174
|
+
forwarding the developer API key:
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
from bazhuayu_dataapp import DataApp
|
|
178
|
+
|
|
179
|
+
async with DataApp:
|
|
180
|
+
resources = DataApp.resources()
|
|
181
|
+
browser = await resources.browser(session_timeout=900)
|
|
182
|
+
ws_url, headers = await browser.connection()
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Resource handles are owned by the client. Close a handle when it is no longer
|
|
186
|
+
needed, or close the client to release all remaining handles and its execution.
|
|
187
|
+
`ProxyResource.rotate_credentials()` rotates only the temporary DataOS gateway
|
|
188
|
+
username/password. It does not claim to replace the supplier session or exit IP.
|
|
189
|
+
Creation requests accept an `idempotency_key`; reuse the same value only when
|
|
190
|
+
retrying the same logical creation after an uncertain transport outcome. A
|
|
191
|
+
browser call also gets an allocation `slot_id`, so independent calls do not
|
|
192
|
+
share a CDP session. By default the slot is derived from the idempotency key;
|
|
193
|
+
reusing that key safely replays the same logical creation. If a slot is supplied
|
|
194
|
+
explicitly, reuse it together with the key. One client rejects a second live
|
|
195
|
+
handle for the same remote browser so closing one crawler cannot stop another's
|
|
196
|
+
shared session. Proxy leases use the same single-live-handle rule.
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
## Managed CAPTCHA resources
|
|
200
|
+
|
|
201
|
+
The default SDK path is the platform-managed cloud API below. Supplier
|
|
202
|
+
credentials stay in Resource Proxy. A native browser extension is an explicit
|
|
203
|
+
advanced option for developers who supply and manage their own vendor account;
|
|
204
|
+
it is not enabled by local API-Key setup.
|
|
205
|
+
|
|
206
|
+
Managed CAPTCHA calls use the overseas Resource Proxy node by default while
|
|
207
|
+
retaining the caller's Bazhuayu account and Billing environment. Creation and
|
|
208
|
+
polling stay on that node. Pass the same explicit `network_preference` to both
|
|
209
|
+
operations only when testing another configured node.
|
|
210
|
+
|
|
211
|
+
The same execution can call `create_captcha_task`, `get_captcha_task`, or
|
|
212
|
+
`solve_captcha`. For image recognition use `type="image_to_text"`, a one-line
|
|
213
|
+
Base64 `image_body`, and optional `capmonster_module="botdetect"` (or another
|
|
214
|
+
configured module). Module selection is a recognizer parameter, not webpage
|
|
215
|
+
CAPTCHA detection. Reuse the same `idempotency_key` when retrying a submission;
|
|
216
|
+
never automatically resubmit an unknown outcome with a new key.
|
|
217
|
+
|
|
218
|
+
`CaptchaTask` returns `node_id/network`; use the creating node for all polls.
|
|
219
|
+
Solutions are excluded from repr. A solver answer still requires validation by
|
|
220
|
+
the target site and does not prove business acquisition success.
|
|
221
|
+
|
|
222
|
+
`captcha_plugin_grant(allowed_types=["image_to_text"], ttl_seconds=300)` returns
|
|
223
|
+
an adapter URL and a secret short-lived key for the explicitly managed extension.
|
|
224
|
+
Other canonical types are `turnstile`, `recaptcha_v2`, and
|
|
225
|
+
`recaptcha_v2_enterprise`; `allowed_hosts` can narrow widget task sites. This key
|
|
226
|
+
cannot authenticate IP, Browser, model, or execution APIs. Its
|
|
227
|
+
`protocol_version` is currently integer `1`. The extension must use the adapter
|
|
228
|
+
for create/poll/credit checks, preserve `dataosRequestId` across retries, and
|
|
229
|
+
return opaque `taskId` unchanged; changing an original extension's base URL alone
|
|
230
|
+
is insufficient. There is no upstream vendor credential in the grant.
|
|
231
|
+
|
|
232
|
+
## Local debug billing
|
|
233
|
+
|
|
234
|
+
For opted-in local executions, the SDK logs one warning before the first
|
|
235
|
+
managed IP lease request, CAPTCHA submission, plugin grant, or model request.
|
|
236
|
+
IP traffic, CAPTCHA solves, and model requests can charge the developer
|
|
237
|
+
account. Pod cost appears separately in cloud debug.
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
async with ResourceProxy.from_env() as resources:
|
|
241
|
+
completion = await resources.chat_completion({
|
|
242
|
+
"model": "your-model-alias",
|
|
243
|
+
"messages": [{"role": "user", "content": "Hello"}],
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
receipt = await resources.resource_charge()
|
|
247
|
+
if receipt is not None:
|
|
248
|
+
print(receipt["state"], receipt["currency"], receipt["expected_amount"], receipt["actual_amount"])
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Read `resource_charge()` during the execution or after it closes. Expected
|
|
252
|
+
and actual amounts retain the service's decimal strings. Resource costs will be
|
|
253
|
+
deducted from developer earnings at settlement, and the remaining earnings will be
|
|
254
|
+
paid out after deduction. `DEFERRED` means the cost has been recorded for deduction;
|
|
255
|
+
it does not confirm a completed deduction. An `actual_amount` of `None` means there
|
|
256
|
+
is no confirmed wallet amount. `resource_charge()`
|
|
257
|
+
returns `None` when managed billing is disabled for the execution or the
|
|
258
|
+
server predates managed billing. A `None` receipt is an unavailable receipt
|
|
259
|
+
payload, not proof that the resource was free or that no charge was recorded.
|
|
260
|
+
|
|
261
|
+
## Managed model requests
|
|
262
|
+
|
|
263
|
+
Use `chat_completion()` with the local client or with `DataApp.resources()`
|
|
264
|
+
in a cloud Run. The helper sends one non-streaming request. Omit `stream` or
|
|
265
|
+
set it to `False`. If your caller may retry after a transport error, pass a
|
|
266
|
+
stable `idempotency_key` and reuse it for the same logical request. The
|
|
267
|
+
helper generates a key when you omit it.
|
|
268
|
+
|
|
269
|
+
The direct HTTP/SSE endpoint `/v1/model-proxy/chat/completions` uses the
|
|
270
|
+
execution identity. Raw clients must send `Idempotency-Key` for managed
|
|
271
|
+
billing and reuse it on retries. Replaying a dispatched key returns a
|
|
272
|
+
conflict. See the [server contract](../../docs/resources/captcha-model.md)
|
|
273
|
+
for the inline-image format, model alias policy, and incomplete usage semantics.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Prefer `python -m dataapp_resource_proxy configure`: it prompts without echo,
|
|
2
|
+
# stores this value outside the project, and applies private file permissions.
|
|
3
|
+
# This environment variable is the explicit process override. Never commit a
|
|
4
|
+
# real value, paste it into chat, or package it with a Data App.
|
|
5
|
+
DATAAPP_API_KEY=replace-with-developer-api-key
|
|
6
|
+
|
|
7
|
+
# Account Center > API Keys:
|
|
8
|
+
# pre: https://pre.bazhuayu.com/console/account-center/api-keys
|
|
9
|
+
# production: https://www.bazhuayu.com/console/account-center/api-keys
|
|
10
|
+
|
|
11
|
+
# Local debug defaults to bazhuayu_pre. These access profiles are optional;
|
|
12
|
+
# overseas profiles keep the same Bazhuayu account and Billing identity.
|
|
13
|
+
# DATAAPP_ENVIRONMENT=bazhuayu_overseas_pre
|
|
14
|
+
|
|
15
|
+
# Pre node addresses are built in. DATAOS_* URL variables remain expert
|
|
16
|
+
# transport overrides for isolated tests and verified production deployments.
|
|
17
|
+
# Uncomment explicit URLs only to override automatic pre-node selection or to
|
|
18
|
+
# configure a verified production deployment. Supplying one regional URL leaves
|
|
19
|
+
# the other region unconfigured.
|
|
20
|
+
# DATAOS_RESOURCE_PROXY_URL=https://single-node.example.com
|
|
21
|
+
# DATAOS_RESOURCE_PROXY_DOMESTIC_URL=https://domestic-node.example.com
|
|
22
|
+
# DATAOS_RESOURCE_PROXY_OVERSEAS_URL=https://overseas-node.example.com
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dataapp-resource-proxy"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Run-scoped client for managed browser, proxy and CAPTCHA resources"
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
dependencies = ["httpx>=0.28,<1"]
|
|
11
|
+
|
|
12
|
+
[dependency-groups]
|
|
13
|
+
dev = ["pytest>=8,<10", "pytest-asyncio>=0.24,<2", "ruff>=0.9", "mypy>=1.13"]
|
|
14
|
+
|
|
15
|
+
[tool.hatch.build.targets.wheel]
|
|
16
|
+
packages = ["src/dataapp_resource_proxy"]
|
|
17
|
+
|
|
18
|
+
[tool.pytest.ini_options]
|
|
19
|
+
asyncio_mode = "auto"
|
|
20
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
21
|
+
testpaths = ["tests"]
|
|
22
|
+
|
|
23
|
+
[tool.ruff]
|
|
24
|
+
target-version = "py311"
|
|
25
|
+
line-length = 100
|
|
26
|
+
|
|
27
|
+
[tool.ruff.lint]
|
|
28
|
+
select = ["E", "F", "I", "UP", "B"]
|
|
29
|
+
|
|
30
|
+
[tool.mypy]
|
|
31
|
+
python_version = "3.11"
|
|
32
|
+
check_untyped_defs = true
|
|
33
|
+
ignore_missing_imports = true
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Client for DataOS managed runtime resources."""
|
|
2
|
+
|
|
3
|
+
from .client import ResourceProxy, ResourceTransport
|
|
4
|
+
from .errors import ResourceProxyError
|
|
5
|
+
from .handles import BrowserResource, CaptchaPluginGrant, CaptchaTask, ProxyResource
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"BrowserResource",
|
|
9
|
+
"CaptchaTask",
|
|
10
|
+
"CaptchaPluginGrant",
|
|
11
|
+
"ProxyResource",
|
|
12
|
+
"ResourceProxy",
|
|
13
|
+
"ResourceProxyError",
|
|
14
|
+
"ResourceTransport",
|
|
15
|
+
]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Command-line helpers for local DataApp resource configuration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import getpass
|
|
7
|
+
import os
|
|
8
|
+
import warnings
|
|
9
|
+
from collections.abc import Sequence
|
|
10
|
+
|
|
11
|
+
from ._local_config import (
|
|
12
|
+
load_project_config,
|
|
13
|
+
resolve_config_environment,
|
|
14
|
+
save_local_config,
|
|
15
|
+
)
|
|
16
|
+
from .errors import ResourceProxyError
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _configure() -> int:
|
|
20
|
+
try:
|
|
21
|
+
project = load_project_config(os.environ)
|
|
22
|
+
environment = resolve_config_environment(os.environ, project)
|
|
23
|
+
except ResourceProxyError as error:
|
|
24
|
+
print(f"配置错误:{error}")
|
|
25
|
+
return 2
|
|
26
|
+
if environment is None:
|
|
27
|
+
print(
|
|
28
|
+
"未找到当前项目的 .dataapp-sdk.json。请在下载的 SDK 项目根目录运行,"
|
|
29
|
+
"或为独立项目显式设置 DATAAPP_ENVIRONMENT。"
|
|
30
|
+
)
|
|
31
|
+
return 2
|
|
32
|
+
print("平台托管 IP 代理和验证码服务会按实际用量产生资源费用。")
|
|
33
|
+
if project is not None:
|
|
34
|
+
print(f"请从当前平台账户中心获取 API Key:{project.api_keys_url}")
|
|
35
|
+
answer = input("确认在本地调试中使用这些收费资源?[y/N] ").strip().lower()
|
|
36
|
+
if answer not in {"y", "yes"}:
|
|
37
|
+
print("未保存配置,也不会发起任何托管资源请求。")
|
|
38
|
+
return 1
|
|
39
|
+
try:
|
|
40
|
+
with warnings.catch_warnings():
|
|
41
|
+
warnings.simplefilter("error", getpass.GetPassWarning)
|
|
42
|
+
api_key = getpass.getpass("请粘贴账户中心的 API Key(输入不会显示):").strip()
|
|
43
|
+
except (EOFError, KeyboardInterrupt, getpass.GetPassWarning):
|
|
44
|
+
print("当前终端无法安全隐藏输入;未保存配置。请在交互式终端重新运行。")
|
|
45
|
+
return 2
|
|
46
|
+
if not api_key:
|
|
47
|
+
print("API Key 不能为空;未保存配置。")
|
|
48
|
+
return 2
|
|
49
|
+
path = save_local_config(api_key, environment=environment)
|
|
50
|
+
print(f"配置已安全保存到 {path},文件权限已设置为 600。")
|
|
51
|
+
return 0
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
55
|
+
parser = argparse.ArgumentParser(prog="python -m dataapp_resource_proxy")
|
|
56
|
+
commands = parser.add_subparsers(dest="command", required=True)
|
|
57
|
+
commands.add_parser("configure", help="configure local managed resources securely")
|
|
58
|
+
options = parser.parse_args(argv)
|
|
59
|
+
if options.command == "configure":
|
|
60
|
+
return _configure()
|
|
61
|
+
return 2
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__":
|
|
65
|
+
raise SystemExit(main())
|