99import click
1010
1111import steamship
12- from steamship import PackageInstance , Steamship , SteamshipError
12+ from steamship import PackageInstance , Steamship , SteamshipError , Workspace
1313from steamship .base .configuration import DEFAULT_WEB_BASE , Configuration
1414from steamship .cli .create_instance import (
1515 config_str_to_dict ,
@@ -46,6 +46,30 @@ def initialize(suppress_message: bool = False):
4646 click .echo (f"Steamship Python CLI version { steamship .__version__ } " )
4747
4848
49+ def initialize_and_get_client_and_prep_project ():
50+ initialize ()
51+ client = None
52+ try :
53+ client = Steamship ()
54+ except SteamshipError as e :
55+ click .secho (e .message , fg = "red" )
56+ click .get_current_context ().abort ()
57+
58+ user = User .current (client )
59+ if path .exists ("steamship.json" ):
60+ manifest = Manifest .load_manifest ()
61+ else :
62+ manifest = manifest_init_wizard (client )
63+ manifest .save ()
64+
65+ if not path .exists ("requirements.txt" ):
66+ requirements_init_wizard ()
67+
68+ update_config_template (manifest )
69+
70+ return client , user , manifest
71+
72+
4973@click .command ()
5074def login ():
5175 """Log in to Steamship, creating ~/.steamship.json"""
@@ -208,9 +232,29 @@ def _run_web_interface(base_url: str) -> str:
208232 return web_url
209233
210234
211- def serve_local (
235+ def register_locally_running_package_with_engine (
236+ client : Steamship ,
237+ ngrok_api_url : str ,
238+ package_handle : str ,
239+ manifest : Manifest ,
240+ config : Optional [str ] = None ,
241+ ) -> PackageInstance :
242+ """Registers the locally running package with the Steamship Engine."""
243+
244+ # Register the Instance in the Engine
245+ invocable_config , is_file = config_str_to_dict (config )
246+ set_unset_params (config , invocable_config , is_file , manifest )
247+ package_instance = PackageInstance .create_local_development_instance (
248+ client ,
249+ local_development_url = ngrok_api_url ,
250+ package_handle = package_handle ,
251+ config = invocable_config ,
252+ )
253+ return package_instance
254+
255+
256+ def serve_local ( # noqa: C901
212257 port : int = 8443 ,
213- instance_handle : Optional [str ] = None ,
214258 no_ngrok : Optional [bool ] = False ,
215259 no_repl : Optional [bool ] = False ,
216260 no_ui : Optional [bool ] = False ,
@@ -220,32 +264,74 @@ def serve_local(
220264 """Serve the invocable on localhost. Useful for debugging locally."""
221265 dev_logging_handler = DevelopmentLoggingHandler .init_and_take_root ()
222266
223- initialize ()
224267 click .secho ("Running your project...\n " )
225268
226- # Report the logs
269+ client , user , manifest = initialize_and_get_client_and_prep_project ()
270+
271+ if workspace :
272+ workspace_obj = Workspace .get (client , handle = workspace )
273+ else :
274+ workspace_obj = Workspace .get (client )
275+ workspace = workspace_obj .handle
276+
277+ # Make sure we're running a package.
278+ if manifest .type != DeployableType .PACKAGE :
279+ click .secho (
280+ f"⚠️ Must run `ship serve local` in a folder with a Steamship Package. Found: { manifest .type } "
281+ )
282+ exit (- 1 )
283+
284+ # Make sure we have a package name -- this allows us to register the running copy with the engine.
285+ deployer = PackageDeployer ()
286+ deployable = deployer .create_or_fetch_deployable (client , user , manifest )
287+
288+ # Report the logs output file.
227289 click .secho (f"📝 Log file: { dev_logging_handler .log_filename } " )
228290
229291 # Start the NGROK connection
230292 ngrok_api_url = None
293+ public_api_url = None
294+
231295 if not no_ngrok :
232296 ngrok_api_url = _run_ngrok (port )
233- click .secho (f"🌎 Public API: { ngrok_api_url } " )
297+
298+ # It requires a trailing slash
299+ if ngrok_api_url [- 1 ] != "/" :
300+ ngrok_api_url = ngrok_api_url + "/"
301+
302+ registered_instance = register_locally_running_package_with_engine (
303+ client = client ,
304+ ngrok_api_url = ngrok_api_url ,
305+ package_handle = deployable .handle ,
306+ manifest = manifest ,
307+ config = config ,
308+ )
309+
310+ # Notes:
311+ # 1. registered_instance.invocation_url is the NGROK URL, not the Steamship Proxy URL.
312+ # 2. The public_api_url should still be NGROK, not the Proxy. The local server emulates the Proxy and
313+ # the Proxy blocks this kind of development traffic.
314+
315+ public_api_url = ngrok_api_url
316+ click .secho (f"🌎 Public API: { public_api_url } " )
234317
235318 # Start the local API Server. This has to happen after NGROK because the port & url need to be plummed.
236319 try :
237320 local_api_url = _run_local_server (
238321 local_port = port ,
239- instance_handle = instance_handle ,
322+ instance_handle = registered_instance . handle ,
240323 config = config ,
241324 workspace = workspace ,
242- base_url = ngrok_api_url ,
325+ base_url = public_api_url ,
243326 )
244327 except BaseException as e :
245328 click .secho ("⚠️ Local API: Unable to start local server." )
246329 click .secho (e )
247330 exit (- 1 )
248331
332+ if local_api_url [- 1 ] != "/" :
333+ local_api_url = local_api_url + "/"
334+
249335 if local_api_url :
250336 click .secho (f"🌎 Local API: { local_api_url } " )
251337 else :
@@ -254,7 +340,7 @@ def serve_local(
254340
255341 # Start the web UI
256342 if not no_ui :
257- web_url = _run_web_interface (ngrok_api_url or local_api_url )
343+ web_url = _run_web_interface (public_api_url or local_api_url )
258344 if web_url :
259345 click .secho (f"🌎 Web UI: { web_url } " )
260346
@@ -264,7 +350,7 @@ def serve_local(
264350 time .sleep (1 )
265351 else :
266352 click .secho ("\n 💬 Interactive REPL below. Type to interact.\n " )
267- prompt_url = f"{ local_api_url or ngrok_api_url } / prompt"
353+ prompt_url = f"{ local_api_url or public_api_url } prompt"
268354 repl = HttpREPL (prompt_url = prompt_url , dev_logging_handler = dev_logging_handler )
269355 repl .run ()
270356
@@ -337,7 +423,6 @@ def run(
337423 if environment == "local" :
338424 serve_local (
339425 port = port ,
340- instance_handle = instance_handle ,
341426 no_ngrok = no_ngrok ,
342427 no_repl = no_repl ,
343428 no_ui = no_ui ,
@@ -355,28 +440,10 @@ def run(
355440@click .command ()
356441def deploy ():
357442 """Deploy the package or plugin in this directory"""
358- initialize ()
359- client = None
360- try :
361- client = Steamship ()
362- except SteamshipError as e :
363- click .secho (e .message , fg = "red" )
364- click .get_current_context ().abort ()
365-
366- user = User .current (client )
367- if path .exists ("steamship.json" ):
368- manifest = Manifest .load_manifest ()
369- else :
370- manifest = manifest_init_wizard (client )
371- manifest .save ()
372-
373- if not path .exists ("requirements.txt" ):
374- requirements_init_wizard ()
443+ client , user , manifest = initialize_and_get_client_and_prep_project ()
375444
376445 deployable_type = manifest .type
377446
378- update_config_template (manifest )
379-
380447 deployer = None
381448 if deployable_type == DeployableType .PACKAGE :
382449 deployer = PackageDeployer ()
0 commit comments