service-forge 0.1.24__py3-none-any.whl → 0.1.27__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.
Potentially problematic release.
This version of service-forge might be problematic. Click here for more details.
- service_forge/api/http_api.py +102 -26
- service_forge/api/routers/websocket/websocket_router.py +13 -0
- service_forge/service.py +7 -0
- service_forge/sft/config/injector.py +11 -6
- service_forge/sft/config/sf_metadata.py +26 -27
- service_forge/sft/util/assert_util.py +0 -1
- service_forge/workflow/triggers/fast_api_trigger.py +3 -0
- service_forge/workflow/triggers/websocket_api_trigger.py +40 -32
- {service_forge-0.1.24.dist-info → service_forge-0.1.27.dist-info}/METADATA +1 -1
- {service_forge-0.1.24.dist-info → service_forge-0.1.27.dist-info}/RECORD +12 -12
- {service_forge-0.1.24.dist-info → service_forge-0.1.27.dist-info}/WHEEL +0 -0
- {service_forge-0.1.24.dist-info → service_forge-0.1.27.dist-info}/entry_points.txt +0 -0
service_forge/api/http_api.py
CHANGED
|
@@ -3,7 +3,7 @@ import uvicorn
|
|
|
3
3
|
from fastapi import APIRouter
|
|
4
4
|
from loguru import logger
|
|
5
5
|
from urllib.parse import urlparse
|
|
6
|
-
from fastapi import HTTPException, Request
|
|
6
|
+
from fastapi import HTTPException, Request, WebSocket, WebSocketException
|
|
7
7
|
from fastapi.middleware.cors import CORSMiddleware
|
|
8
8
|
from fastapi.openapi.utils import get_openapi
|
|
9
9
|
from service_forge.api.routers.websocket.websocket_router import websocket_router
|
|
@@ -36,6 +36,88 @@ def is_trusted_origin(origin_host: str, host: str, trusted_root: str = "ring.shi
|
|
|
36
36
|
)
|
|
37
37
|
|
|
38
38
|
|
|
39
|
+
def validate_auth_from_headers(
|
|
40
|
+
headers: dict,
|
|
41
|
+
origin: str | None,
|
|
42
|
+
scheme: str,
|
|
43
|
+
host: str,
|
|
44
|
+
trusted_domain: str = "ring.shiweinan.com",
|
|
45
|
+
) -> tuple[str | None, str | None]:
|
|
46
|
+
"""
|
|
47
|
+
Validate authentication from headers and return user_id and token.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
headers: Dictionary of headers (can be from Request or WebSocket)
|
|
51
|
+
origin: Origin header value
|
|
52
|
+
scheme: URL scheme (http/https/ws/wss)
|
|
53
|
+
host: Host header value
|
|
54
|
+
trusted_domain: Trusted domain for origin validation
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
tuple: (user_id, auth_token) - user_id can be None if not authenticated and not same origin
|
|
58
|
+
"""
|
|
59
|
+
is_same_origin = False
|
|
60
|
+
|
|
61
|
+
logger.debug(f"origin {origin}, host:{host}")
|
|
62
|
+
|
|
63
|
+
if origin and host:
|
|
64
|
+
try:
|
|
65
|
+
parsed_origin = urlparse(origin)
|
|
66
|
+
parsed_host = urlparse(f"{scheme}://{host}")
|
|
67
|
+
is_same_origin = (
|
|
68
|
+
parsed_origin.hostname == parsed_host.hostname
|
|
69
|
+
and parsed_origin.port == parsed_host.port
|
|
70
|
+
and is_trusted_origin(parsed_origin.hostname, parsed_host.hostname, trusted_domain)
|
|
71
|
+
)
|
|
72
|
+
except Exception:
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
user_id = headers.get("X-User-ID")
|
|
76
|
+
token = headers.get("X-User-Token")
|
|
77
|
+
|
|
78
|
+
if not is_same_origin:
|
|
79
|
+
# For cross-origin requests, user_id is required
|
|
80
|
+
if not user_id:
|
|
81
|
+
return None, None
|
|
82
|
+
return user_id, token
|
|
83
|
+
else:
|
|
84
|
+
# For same-origin requests, user_id defaults to "0" if not provided
|
|
85
|
+
return user_id if user_id else "0", token
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
async def authenticate_websocket(
|
|
89
|
+
websocket: WebSocket,
|
|
90
|
+
trusted_domain: str = "ring.shiweinan.com",
|
|
91
|
+
) -> None:
|
|
92
|
+
"""
|
|
93
|
+
Authenticate WebSocket connection and set user_id and auth_token in websocket.state.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
websocket: WebSocket instance
|
|
97
|
+
trusted_domain: Trusted domain for origin validation
|
|
98
|
+
|
|
99
|
+
Raises:
|
|
100
|
+
WebSocketException: If authentication fails
|
|
101
|
+
"""
|
|
102
|
+
origin = websocket.headers.get("origin") or websocket.headers.get("referer")
|
|
103
|
+
scheme = websocket.url.scheme
|
|
104
|
+
host = websocket.headers.get("host", "")
|
|
105
|
+
|
|
106
|
+
user_id, token = validate_auth_from_headers(
|
|
107
|
+
websocket.headers,
|
|
108
|
+
origin,
|
|
109
|
+
scheme,
|
|
110
|
+
host,
|
|
111
|
+
trusted_domain,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
if user_id is None:
|
|
115
|
+
raise WebSocketException(code=1008, reason="Unauthorized")
|
|
116
|
+
|
|
117
|
+
websocket.state.user_id = user_id
|
|
118
|
+
websocket.state.auth_token = token
|
|
119
|
+
|
|
120
|
+
|
|
39
121
|
def create_app(
|
|
40
122
|
app: FastAPI | None = None,
|
|
41
123
|
routers: list[APIRouter] | None = None,
|
|
@@ -77,6 +159,10 @@ def create_app(
|
|
|
77
159
|
for router in routers:
|
|
78
160
|
app.include_router(router)
|
|
79
161
|
|
|
162
|
+
# Store auth configuration in app.state for WebSocket endpoints to access
|
|
163
|
+
app.state.enable_auth_middleware = enable_auth_middleware
|
|
164
|
+
app.state.trusted_domain = trusted_domain
|
|
165
|
+
|
|
80
166
|
# Always include WebSocket router
|
|
81
167
|
app.include_router(websocket_router)
|
|
82
168
|
|
|
@@ -100,31 +186,20 @@ def create_app(
|
|
|
100
186
|
origin = request.headers.get("origin") or request.headers.get("referer")
|
|
101
187
|
scheme = request.url.scheme
|
|
102
188
|
host = request.headers.get("host", "")
|
|
103
|
-
is_same_origin = False
|
|
104
189
|
|
|
105
|
-
|
|
190
|
+
user_id, token = validate_auth_from_headers(
|
|
191
|
+
request.headers,
|
|
192
|
+
origin,
|
|
193
|
+
scheme,
|
|
194
|
+
host,
|
|
195
|
+
trusted_domain,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
if user_id is None:
|
|
199
|
+
raise HTTPException(status_code=401, detail="Unauthorized")
|
|
106
200
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
parsed_origin = urlparse(origin)
|
|
110
|
-
parsed_host = urlparse(f"{scheme}://{host}")
|
|
111
|
-
is_same_origin = (
|
|
112
|
-
parsed_origin.hostname == parsed_host.hostname
|
|
113
|
-
and parsed_origin.port == parsed_host.port
|
|
114
|
-
and is_trusted_origin(parsed_origin.hostname, parsed_host.hostname, trusted_domain)
|
|
115
|
-
)
|
|
116
|
-
except Exception:
|
|
117
|
-
pass # If parsing fails, continue with default behavior
|
|
118
|
-
if not is_same_origin:
|
|
119
|
-
headers = request.headers
|
|
120
|
-
user_id = headers.get("X-User-ID")
|
|
121
|
-
if not user_id:
|
|
122
|
-
raise HTTPException(status_code=401, detail="Unauthorized")
|
|
123
|
-
|
|
124
|
-
request.state.user_id = user_id
|
|
125
|
-
else:
|
|
126
|
-
# Same-origin requests can skip auth, but still set default user_id
|
|
127
|
-
request.state.user_id = "0" # Can be None or default value as needed
|
|
201
|
+
request.state.user_id = user_id
|
|
202
|
+
request.state.auth_token = token
|
|
128
203
|
|
|
129
204
|
return await call_next(request)
|
|
130
205
|
|
|
@@ -147,6 +222,7 @@ async def start_fastapi_server(host: str, port: int):
|
|
|
147
222
|
|
|
148
223
|
try:
|
|
149
224
|
metadata = load_metadata("sf-meta.yaml")
|
|
150
|
-
fastapi_app = create_app(enable_auth_middleware=
|
|
225
|
+
fastapi_app = create_app(enable_auth_middleware=metadata.enable_auth_middleware, root_path=f"/api/v1/{get_service_url_name(metadata.name, metadata.version)}")
|
|
151
226
|
except Exception as e:
|
|
152
|
-
|
|
227
|
+
logger.warning(f"Failed to load metadata, using default configuration: {e}")
|
|
228
|
+
fastapi_app = create_app(enable_auth_middleware=True, root_path=None)
|
|
@@ -9,6 +9,19 @@ websocket_router = APIRouter()
|
|
|
9
9
|
|
|
10
10
|
@websocket_router.websocket("/sdk/ws")
|
|
11
11
|
async def sdk_websocket_endpoint(websocket: WebSocket):
|
|
12
|
+
# Authenticate WebSocket connection before accepting
|
|
13
|
+
# Get trusted_domain from app.state if available
|
|
14
|
+
# trusted_domain = getattr(websocket.app.state, "trusted_domain", "ring.shiweinan.com")
|
|
15
|
+
# enable_auth = getattr(websocket.app.state, "enable_auth_middleware", True)
|
|
16
|
+
|
|
17
|
+
# if enable_auth:
|
|
18
|
+
# from service_forge.api.http_api import authenticate_websocket
|
|
19
|
+
# await authenticate_websocket(websocket, trusted_domain)
|
|
20
|
+
# else:
|
|
21
|
+
# # If auth is disabled, set default values
|
|
22
|
+
# websocket.state.user_id = websocket.headers.get("X-User-ID", "0")
|
|
23
|
+
# websocket.state.auth_token = websocket.headers.get("X-User-Token")
|
|
24
|
+
|
|
12
25
|
await websocket.accept()
|
|
13
26
|
try:
|
|
14
27
|
while True:
|
service_forge/service.py
CHANGED
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
import asyncio
|
|
5
5
|
import threading
|
|
6
6
|
import uuid
|
|
7
|
+
from importlib.metadata import version
|
|
7
8
|
from loguru import logger
|
|
8
9
|
from typing import Callable, AsyncIterator, Awaitable, Any, TYPE_CHECKING
|
|
9
10
|
from service_forge.workflow.node import node_register
|
|
@@ -260,6 +261,12 @@ class Service:
|
|
|
260
261
|
|
|
261
262
|
@staticmethod
|
|
262
263
|
def from_config(metadata: SfMetadata, service_env: dict[str, Any] = None, config: ServiceConfig = None) -> Service:
|
|
264
|
+
try:
|
|
265
|
+
service_forge_version = version("service-forge")
|
|
266
|
+
logger.info(f"service-forge version: {service_forge_version}")
|
|
267
|
+
except Exception as e:
|
|
268
|
+
logger.warning(f"Failed to get service-forge version: {e}")
|
|
269
|
+
|
|
263
270
|
if config is not None:
|
|
264
271
|
config_path = None
|
|
265
272
|
else:
|
|
@@ -133,9 +133,14 @@ class Injector:
|
|
|
133
133
|
f.write(new_content)
|
|
134
134
|
|
|
135
135
|
def inject(self) -> None:
|
|
136
|
-
self.
|
|
137
|
-
|
|
138
|
-
self.
|
|
139
|
-
|
|
140
|
-
self.
|
|
141
|
-
|
|
136
|
+
if self.metadata.inject.deployment:
|
|
137
|
+
self.inject_deployment()
|
|
138
|
+
if self.metadata.inject.service_config:
|
|
139
|
+
self.inject_service_config()
|
|
140
|
+
if self.metadata.inject.ingress:
|
|
141
|
+
self.inject_ingress()
|
|
142
|
+
if self.metadata.inject.dockerfile:
|
|
143
|
+
self.inject_dockerfile()
|
|
144
|
+
if self.metadata.inject.pyproject_toml:
|
|
145
|
+
self.inject_pyproject_toml()
|
|
146
|
+
self.clear_start_sh()
|
|
@@ -1,30 +1,29 @@
|
|
|
1
|
-
from
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import yaml
|
|
3
|
+
from pydantic import BaseModel
|
|
2
4
|
|
|
3
|
-
class
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
5
|
+
class SfMetadataInject(BaseModel):
|
|
6
|
+
deployment: bool = True
|
|
7
|
+
service_config: bool = True
|
|
8
|
+
ingress: bool = True
|
|
9
|
+
dockerfile: bool = True
|
|
10
|
+
pyproject_toml: bool = True
|
|
11
|
+
|
|
12
|
+
class SfMetadata(BaseModel):
|
|
13
|
+
name: str
|
|
14
|
+
version: str
|
|
15
|
+
description: str
|
|
16
|
+
service_config: str
|
|
17
|
+
config_only: bool
|
|
18
|
+
env: list[dict]
|
|
19
|
+
inject: SfMetadataInject = SfMetadataInject()
|
|
20
|
+
enable_auth_middleware: bool = True
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
def from_yaml_file(cls, filepath: str) -> SfMetadata:
|
|
24
|
+
with open(filepath, 'r', encoding='utf-8') as f:
|
|
25
|
+
data = yaml.safe_load(f)
|
|
26
|
+
return cls(**data)
|
|
19
27
|
|
|
20
28
|
def load_metadata(path: str) -> SfMetadata:
|
|
21
|
-
|
|
22
|
-
data = OmegaConf.load(file)
|
|
23
|
-
return SfMetadata(
|
|
24
|
-
name=data.get('name'),
|
|
25
|
-
version=data.get('version'),
|
|
26
|
-
description=data.get('description'),
|
|
27
|
-
service_config=data.get('service_config'),
|
|
28
|
-
config_only=data.get('config_only'),
|
|
29
|
-
env=data.get('env', []),
|
|
30
|
-
)
|
|
29
|
+
return SfMetadata.from_yaml_file(path)
|
|
@@ -26,6 +26,7 @@ class FastAPITrigger(Trigger):
|
|
|
26
26
|
DEFAULT_OUTPUT_PORTS = [
|
|
27
27
|
Port("trigger", bool),
|
|
28
28
|
Port("user_id", int),
|
|
29
|
+
Port("token", str),
|
|
29
30
|
Port("data", Any),
|
|
30
31
|
]
|
|
31
32
|
|
|
@@ -72,6 +73,7 @@ class FastAPITrigger(Trigger):
|
|
|
72
73
|
self.trigger_queue.put_nowait({
|
|
73
74
|
"id": task_id,
|
|
74
75
|
"user_id": getattr(request.state, "user_id", None),
|
|
76
|
+
"token": getattr(request.state, "auth_token", None),
|
|
75
77
|
"data": converted_data,
|
|
76
78
|
})
|
|
77
79
|
|
|
@@ -169,6 +171,7 @@ class FastAPITrigger(Trigger):
|
|
|
169
171
|
try:
|
|
170
172
|
trigger = await self.trigger_queue.get()
|
|
171
173
|
self.prepare_output_edges(self.get_output_port_by_name('user_id'), trigger['user_id'])
|
|
174
|
+
self.prepare_output_edges(self.get_output_port_by_name('token'), trigger['token'])
|
|
172
175
|
self.prepare_output_edges(self.get_output_port_by_name('data'), trigger['data'])
|
|
173
176
|
yield self.trigger(trigger['id'])
|
|
174
177
|
except Exception as e:
|
|
@@ -9,6 +9,7 @@ from fastapi import FastAPI, WebSocket, WebSocketDisconnect
|
|
|
9
9
|
from service_forge.workflow.port import Port
|
|
10
10
|
from google.protobuf.message import Message
|
|
11
11
|
from google.protobuf.json_format import MessageToJson
|
|
12
|
+
from service_forge.api.http_api import authenticate_websocket
|
|
12
13
|
|
|
13
14
|
class WebSocketAPITrigger(Trigger):
|
|
14
15
|
DEFAULT_INPUT_PORTS = [
|
|
@@ -19,6 +20,8 @@ class WebSocketAPITrigger(Trigger):
|
|
|
19
20
|
|
|
20
21
|
DEFAULT_OUTPUT_PORTS = [
|
|
21
22
|
Port("trigger", bool),
|
|
23
|
+
Port("user_id", int),
|
|
24
|
+
Port("token", str),
|
|
22
25
|
Port("data", Any),
|
|
23
26
|
]
|
|
24
27
|
|
|
@@ -36,6 +39,20 @@ class WebSocketAPITrigger(Trigger):
|
|
|
36
39
|
)
|
|
37
40
|
return result
|
|
38
41
|
|
|
42
|
+
async def send_message(
|
|
43
|
+
self,
|
|
44
|
+
websocket: WebSocket,
|
|
45
|
+
type: str,
|
|
46
|
+
task_id: uuid.UUID,
|
|
47
|
+
data: Any,
|
|
48
|
+
):
|
|
49
|
+
message = {
|
|
50
|
+
"type": type,
|
|
51
|
+
"task_id": str(task_id),
|
|
52
|
+
"data": data
|
|
53
|
+
}
|
|
54
|
+
await websocket.send_text(json.dumps(message))
|
|
55
|
+
|
|
39
56
|
async def handle_stream_output(
|
|
40
57
|
self,
|
|
41
58
|
websocket: WebSocket,
|
|
@@ -46,12 +63,7 @@ class WebSocketAPITrigger(Trigger):
|
|
|
46
63
|
item = await self.stream_queues[task_id].get()
|
|
47
64
|
|
|
48
65
|
if item.is_error:
|
|
49
|
-
|
|
50
|
-
"type": "stream_error",
|
|
51
|
-
"task_id": str(task_id),
|
|
52
|
-
"detail": str(item.result)
|
|
53
|
-
}
|
|
54
|
-
await websocket.send_text(json.dumps(error_response))
|
|
66
|
+
await self.send_message(websocket, "stream_error", task_id, str(item.result))
|
|
55
67
|
break
|
|
56
68
|
|
|
57
69
|
if item.is_end:
|
|
@@ -65,18 +77,9 @@ class WebSocketAPITrigger(Trigger):
|
|
|
65
77
|
data = serialized
|
|
66
78
|
else:
|
|
67
79
|
data = serialized
|
|
68
|
-
|
|
69
|
-
end_response = {
|
|
70
|
-
"type": "stream_end",
|
|
71
|
-
"task_id": str(task_id),
|
|
72
|
-
"data": data
|
|
73
|
-
}
|
|
80
|
+
await self.send_message(websocket, "stream_end", task_id, data)
|
|
74
81
|
else:
|
|
75
|
-
|
|
76
|
-
"type": "stream_end",
|
|
77
|
-
"task_id": str(task_id)
|
|
78
|
-
}
|
|
79
|
-
await websocket.send_text(json.dumps(end_response))
|
|
82
|
+
await self.send_message(websocket, "stream_end", task_id, None)
|
|
80
83
|
break
|
|
81
84
|
|
|
82
85
|
# Send stream data
|
|
@@ -89,23 +92,10 @@ class WebSocketAPITrigger(Trigger):
|
|
|
89
92
|
else:
|
|
90
93
|
data = serialized
|
|
91
94
|
|
|
92
|
-
|
|
93
|
-
"type": "stream",
|
|
94
|
-
"task_id": str(task_id),
|
|
95
|
-
"data": data
|
|
96
|
-
}
|
|
97
|
-
await websocket.send_text(json.dumps(stream_response))
|
|
95
|
+
await self.send_message(websocket, "stream", task_id, data)
|
|
98
96
|
except Exception as e:
|
|
99
97
|
logger.error(f"Error handling stream output for task {task_id}: {e}")
|
|
100
|
-
|
|
101
|
-
"type": "stream_error",
|
|
102
|
-
"task_id": str(task_id),
|
|
103
|
-
"detail": str(e)
|
|
104
|
-
}
|
|
105
|
-
try:
|
|
106
|
-
await websocket.send_text(json.dumps(error_response))
|
|
107
|
-
except Exception:
|
|
108
|
-
pass
|
|
98
|
+
await self.send_message(websocket, "stream_error", task_id, str(e))
|
|
109
99
|
finally:
|
|
110
100
|
if task_id in self.stream_queues:
|
|
111
101
|
del self.stream_queues[task_id]
|
|
@@ -120,6 +110,8 @@ class WebSocketAPITrigger(Trigger):
|
|
|
120
110
|
self.result_queues[task_id] = asyncio.Queue()
|
|
121
111
|
self.stream_queues[task_id] = asyncio.Queue()
|
|
122
112
|
|
|
113
|
+
logger.info('user_id', getattr(websocket.state, "user_id", None), 'token', getattr(websocket.state, "auth_token", None))
|
|
114
|
+
|
|
123
115
|
if data_type is Any:
|
|
124
116
|
converted_data = message_data
|
|
125
117
|
else:
|
|
@@ -136,6 +128,8 @@ class WebSocketAPITrigger(Trigger):
|
|
|
136
128
|
|
|
137
129
|
self.trigger_queue.put_nowait({
|
|
138
130
|
"id": task_id,
|
|
131
|
+
"user_id": getattr(websocket.state, "user_id", None),
|
|
132
|
+
"token": getattr(websocket.state, "auth_token", None),
|
|
139
133
|
"data": converted_data,
|
|
140
134
|
})
|
|
141
135
|
|
|
@@ -143,6 +137,18 @@ class WebSocketAPITrigger(Trigger):
|
|
|
143
137
|
|
|
144
138
|
def _setup_websocket(self, app: FastAPI, path: str, data_type: type) -> None:
|
|
145
139
|
async def websocket_handler(websocket: WebSocket):
|
|
140
|
+
# Authenticate WebSocket connection before accepting
|
|
141
|
+
# Get trusted_domain from app.state if available
|
|
142
|
+
trusted_domain = getattr(app.state, "trusted_domain", "ring.shiweinan.com")
|
|
143
|
+
enable_auth = getattr(app.state, "enable_auth_middleware", True)
|
|
144
|
+
|
|
145
|
+
if enable_auth:
|
|
146
|
+
await authenticate_websocket(websocket, trusted_domain)
|
|
147
|
+
else:
|
|
148
|
+
# If auth is disabled, set default values
|
|
149
|
+
websocket.state.user_id = websocket.headers.get("X-User-ID", "0")
|
|
150
|
+
websocket.state.auth_token = websocket.headers.get("X-User-Token")
|
|
151
|
+
|
|
146
152
|
await websocket.accept()
|
|
147
153
|
|
|
148
154
|
try:
|
|
@@ -178,6 +184,8 @@ class WebSocketAPITrigger(Trigger):
|
|
|
178
184
|
while True:
|
|
179
185
|
try:
|
|
180
186
|
trigger = await self.trigger_queue.get()
|
|
187
|
+
self.prepare_output_edges(self.get_output_port_by_name('user_id'), trigger['user_id'])
|
|
188
|
+
self.prepare_output_edges(self.get_output_port_by_name('token'), trigger['token'])
|
|
181
189
|
self.prepare_output_edges(self.get_output_port_by_name('data'), trigger['data'])
|
|
182
190
|
yield self.trigger(trigger['id'])
|
|
183
191
|
except Exception as e:
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
service_forge/current_service.py,sha256=0YKm7nQiXzUUAc1ToCcbG1QPJfOSNKcOHUpyJ4E3xrY,342
|
|
2
|
-
service_forge/service.py,sha256=
|
|
2
|
+
service_forge/service.py,sha256=lHsZraEH6Ze20QO5v6iW1MO8src8T8JKLFRBXtd0LD0,12933
|
|
3
3
|
service_forge/service_config.py,sha256=zsTdCZ1peMAotjGEVypPos7d-gjwrYoB9x_12g95G4g,1242
|
|
4
4
|
service_forge/api/deprecated_websocket_api.py,sha256=E36-fpUPxzMJ2YGlCPeqwRbryk2FMMbQD_pbb8k1FYI,3343
|
|
5
5
|
service_forge/api/deprecated_websocket_manager.py,sha256=Xiwg3zwXRVi63sXmVH-TgbpL2XH_djyLeo96STm4cNM,16757
|
|
6
|
-
service_forge/api/http_api.py,sha256=
|
|
6
|
+
service_forge/api/http_api.py,sha256=8vcN7oyxwTwu_w1f-Egh2XrFWsm-ci5_gk7KsQiP1iM,7673
|
|
7
7
|
service_forge/api/http_api_doc.py,sha256=ASlxvsIiUzDcMhVoumRjt9CfEMbh0O1U4ZLC9eobLF8,20235
|
|
8
8
|
service_forge/api/kafka_api.py,sha256=PInx2ZzKJRON7EaJFWroXkiOt_UeZY7WE6qK03gq4ak,4599
|
|
9
9
|
service_forge/api/task_manager.py,sha256=9Lk-NV4cBnuv9b8V6GVLWJJ4MCiAwCp5TVAwmYgqXbs,5269
|
|
10
10
|
service_forge/api/routers/feedback/feedback_router.py,sha256=JOJI6kaQYapg4__iA6Eo26_9su48p7R2Kpn422nbsxw,5640
|
|
11
11
|
service_forge/api/routers/service/service_router.py,sha256=hGOT-ScnXR7agHp-F9OFGWiPFjG9f3gl7NBsnayW3JI,5088
|
|
12
12
|
service_forge/api/routers/websocket/websocket_manager.py,sha256=j1AFqzXQhZZyaLQwhvZefXAS-zCOPzLcRMDEuusv6V0,3605
|
|
13
|
-
service_forge/api/routers/websocket/websocket_router.py,sha256=
|
|
13
|
+
service_forge/api/routers/websocket/websocket_router.py,sha256=sPDJriEpD2mqu4508cOaWK7u040sgOdaUFlyiBqCSgc,4447
|
|
14
14
|
service_forge/db/__init__.py,sha256=EWLhH8bYsMOvRF_YXF6FgL3irKA6GZeLxSGvWDRM6f8,85
|
|
15
15
|
service_forge/db/database.py,sha256=WKtZ0MoOnbMw54ohfs9zKsrOZ5_qenLvXkAV_Gr2WOs,10068
|
|
16
16
|
service_forge/db/migrations/feedback_migration.py,sha256=-zQ71TsOlWmQPQo1NKSIu3C1T47v3cfD6IAQ5HE_ffk,4845
|
|
@@ -30,15 +30,15 @@ service_forge/sft/cmd/remote_deploy.py,sha256=AStAlbqGD7XeZFhL0fx2j12YWP_MVbdURb
|
|
|
30
30
|
service_forge/sft/cmd/remote_list_tars.py,sha256=mx6hkNnu0ySMyBX2Qi6blKMj5xnNnrmXq3VD_nERlmw,4176
|
|
31
31
|
service_forge/sft/cmd/service_command.py,sha256=69GMMN61KtuoEFuYzFJ74ivNt8RX8q0I6rbePfJfEwQ,5538
|
|
32
32
|
service_forge/sft/cmd/upload_service.py,sha256=86PvvJSXCZKH4BU6rLytuc45grX-sRnQnOHCo9zUaPY,1232
|
|
33
|
-
service_forge/sft/config/injector.py,sha256
|
|
33
|
+
service_forge/sft/config/injector.py,sha256=V79AW1W_LyU-Hn2QgJlLyTt8tdI3J1t1jS3wRoXfbSo,6581
|
|
34
34
|
service_forge/sft/config/injector_default_files.py,sha256=f7mNJ5Y9yb4e9kjLn414WiQoZrOue9ok_hq_POG4I2o,2717
|
|
35
|
-
service_forge/sft/config/sf_metadata.py,sha256=
|
|
35
|
+
service_forge/sft/config/sf_metadata.py,sha256=RruOe3_6JdxLnzMbmdnOcncxwnmATR-1q3Cn8R9d5eE,782
|
|
36
36
|
service_forge/sft/config/sft_config.py,sha256=MgurtgbcSmyXbGlVX3NG84KD4Hst1gZWHdF9a8zi-6U,7707
|
|
37
37
|
service_forge/sft/file/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
38
|
service_forge/sft/file/ignore_pattern.py,sha256=UrVmR83wOx51XHFcZDTPp15dGYcvMTE5W1m07-SvHpw,2521
|
|
39
39
|
service_forge/sft/file/sft_file_manager.py,sha256=poIM77tZZg7vfwBdCsdQctBbCczVLQePdTwVINEABvE,4337
|
|
40
40
|
service_forge/sft/kubernetes/kubernetes_manager.py,sha256=IF2_X9U-k5Dx7EZuGrJ9lZ85ltbilrrZDfsl8qFyTu4,11339
|
|
41
|
-
service_forge/sft/util/assert_util.py,sha256=
|
|
41
|
+
service_forge/sft/util/assert_util.py,sha256=6XVTsXKxg92ww3heWzuMvTbybGuw1cmTqWqfiSbPAcY,753
|
|
42
42
|
service_forge/sft/util/logger.py,sha256=0Hi74IoxshE-wBgvBa2EZPXYj37tTrUYwlOBd9UMMMs,502
|
|
43
43
|
service_forge/sft/util/name_util.py,sha256=WSYHM6c7SZULXCFON7nmGqsvAPPs_wavd6QjCa4UbRQ,301
|
|
44
44
|
service_forge/sft/util/yaml_utils.py,sha256=9OhJNQlzj_C1NeQoUZVF8qpDovrE7RDWtNXe-H7tuNA,1703
|
|
@@ -74,12 +74,12 @@ service_forge/workflow/nodes/test/if_console_input_node.py,sha256=CtKHkFqr8PN974
|
|
|
74
74
|
service_forge/workflow/nodes/test/time_consuming_node.py,sha256=gB2qw2DdjRf82z1158u36nSnCHrheHaxscAzPRnXNyk,1813
|
|
75
75
|
service_forge/workflow/triggers/__init__.py,sha256=iQ0WEYu6JgL191Y9XslMhZ7jS7JO8bL3SZ9YqIw5LCM,269
|
|
76
76
|
service_forge/workflow/triggers/a2a_api_trigger.py,sha256=Oaw3vRLA8fWZUIQ-h33dYmojmjp4mwNF_0LHqQ_4mZQ,8583
|
|
77
|
-
service_forge/workflow/triggers/fast_api_trigger.py,sha256=
|
|
77
|
+
service_forge/workflow/triggers/fast_api_trigger.py,sha256=bAtnuNkUcB5rApXj7x3oBscdavUnDGTb7lE9OpmtauE,7705
|
|
78
78
|
service_forge/workflow/triggers/kafka_api_trigger.py,sha256=Zv8J75Rmg1-xqxHwpBMBhsm_TWX8p3_rqldk2RVSwVc,1561
|
|
79
79
|
service_forge/workflow/triggers/once_trigger.py,sha256=YmzSQBoKE-8liNFIoDCqi2UdqhHujizsXVDft81_8jA,572
|
|
80
80
|
service_forge/workflow/triggers/period_trigger.py,sha256=JFX3yBjKqoRP55jiulaSG_SPO-zWLMcwEb1BwcKsWUM,767
|
|
81
|
-
service_forge/workflow/triggers/websocket_api_trigger.py,sha256=
|
|
82
|
-
service_forge-0.1.
|
|
83
|
-
service_forge-0.1.
|
|
84
|
-
service_forge-0.1.
|
|
85
|
-
service_forge-0.1.
|
|
81
|
+
service_forge/workflow/triggers/websocket_api_trigger.py,sha256=JmA0NkOjbskvP6j7Oook2VkHvY4r4OdX6CBih7D5NBg,7588
|
|
82
|
+
service_forge-0.1.27.dist-info/METADATA,sha256=8_qXSBKj6S4P15B2mJW1ZXy1I4d6AT4YXOJPtasMTOw,2308
|
|
83
|
+
service_forge-0.1.27.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
84
|
+
service_forge-0.1.27.dist-info/entry_points.txt,sha256=WHntHW7GAyKQUEeMcMvHDZ7_xAb0-cZeAK4iJeu9lm8,51
|
|
85
|
+
service_forge-0.1.27.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|