Skip to content

Commit 2acec42

Browse files
authored
Merge pull request #10 from secus217/main
Add open browser function and dev-no-browser command
2 parents 58e4d82 + ae5af48 commit 2acec42

11 files changed

Lines changed: 530 additions & 138 deletions

File tree

.env.example

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@ KUBERNETES_NAMESPACE=container-engine
2121
DOMAIN_SUFFIX=container-engine.app
2222

2323
# Logging
24-
RUST_LOG=container_engine=debug,tower_http=debug
24+
RUST_LOG=container_engine=debug,tower_http=debug
25+
# Front end path
26+
FRONTEND_PATH=./apps/container-engine-frontend/dist

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ license = "MIT"
77
repository = "https://github.com/ngocbd/Open-Container-Engine"
88

99
[dependencies]
10-
10+
open = "5"
1111
# Web framework
1212
axum = { version = "0.7", features = ["macros", "tracing"] }
1313
tokio = { version = "1.0", features = ["full"] }

apps/container-engine-frontend/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import DeploymentDetailPage from './pages/DeploymentDetailPage';
1010
import ApiKeysPage from './pages/ApiKeysPage';
1111
import AccountSettingsPage from './pages/AccountSettingsPage';
1212
import ProtectedRoute from './components/ProtectedRoute';
13-
import { ToastContainer, toast } from 'react-toastify';
13+
import { ToastContainer } from 'react-toastify';
1414
import 'react-toastify/dist/ReactToastify.css';
1515

1616
function App() {

apps/container-engine-frontend/src/pages/DeploymentDetailPage.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
ClipboardDocumentListIcon,
1212
GlobeAltIcon,
1313
ArrowLeftIcon,
14-
PlayIcon,
1514
StopIcon,
1615
ArrowPathIcon,
1716
ExclamationTriangleIcon,

apps/container-engine-frontend/src/pages/NewDeploymentPage.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ const NewDeploymentPage: React.FC = () => {
6565
replicas,
6666
});
6767
setSuccess(`Deployment '${response.data.app_name}' created! URL: ${response.data.url}`);
68-
if(response.data.id){
69-
navigate(`/deployments/${response.data.id}`);
70-
}
68+
if (response.data.id) {
69+
navigate(`/deployments/${response.data.id}`);
70+
} else return;
7171
} catch (err: any) {
7272
setError(err.response?.data || 'An unexpected error occurred.');
7373
} finally {

setup.sh

Lines changed: 131 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,74 @@ log_warning() {
3939
log_error() {
4040
echo -e "${RED}[ERROR]${NC} $1"
4141
}
42+
# Function to open browser
43+
open_browser() {
44+
local url="${1:-http://localhost:3000}"
45+
46+
log_info "Opening browser at: $url"
47+
48+
# Detect OS and open browser accordingly
49+
case "$OSTYPE" in
50+
linux-gnu*)
51+
# Linux
52+
if command_exists xdg-open; then
53+
xdg-open "$url" 2>/dev/null &
54+
elif command_exists gnome-open; then
55+
gnome-open "$url" 2>/dev/null &
56+
elif command_exists kde-open; then
57+
kde-open "$url" 2>/dev/null &
58+
else
59+
log_warning "Could not detect browser opener. Please open manually: $url"
60+
return 1
61+
fi
62+
;;
63+
darwin*)
64+
# macOS
65+
open "$url" 2>/dev/null &
66+
;;
67+
msys*|cygwin*|mingw*)
68+
# Windows (Git Bash/MinGW)
69+
start "$url" 2>/dev/null &
70+
;;
71+
*)
72+
log_warning "Unknown OS type: $OSTYPE. Please open manually: $url"
73+
return 1
74+
;;
75+
esac
76+
77+
log_success "Browser opened successfully"
78+
}
79+
80+
# Function to wait for server and open browser
81+
wait_and_open_browser() {
82+
local port="${1:-3000}"
83+
local path="${2:-}"
84+
local max_retries=30
85+
local retry_count=0
86+
87+
log_info "Waiting for server to be ready..."
88+
89+
while [ $retry_count -lt $max_retries ]; do
90+
if curl -s -o /dev/null "http://localhost:$port/health" 2>/dev/null; then
91+
log_success "Server is ready!"
92+
open_browser "http://localhost:$port$path"
93+
return 0
94+
fi
95+
96+
sleep 1
97+
retry_count=$((retry_count + 1))
98+
99+
if [ $((retry_count % 5)) -eq 0 ]; then
100+
log_info "Still waiting for server... ($retry_count/$max_retries)"
101+
fi
102+
done
103+
104+
log_warning "Server did not become ready within 30 seconds"
105+
return 1
106+
}
107+
start_dev_no_browser() {
108+
AUTO_OPEN_BROWSER=false start_dev
109+
}
42110

43111
# Show help
44112
show_help() {
@@ -63,7 +131,9 @@ COMMANDS:
63131
db-reset Reset database and volumes
64132
migrate Run database migrations
65133
sqlx-prepare Prepare SQLx queries for offline compilation
66-
dev Start development server
134+
dev Start development server (auto-opens browser)
135+
dev-no-browser Start development server without opening browser
136+
open Open browser to development server
67137
build Build the project
68138
test Run tests
69139
format Format code
@@ -73,12 +143,14 @@ COMMANDS:
73143
docker-up Start all services with Docker
74144
docker-down Stop all Docker services
75145
146+
ENVIRONMENT VARIABLES:
147+
AUTO_OPEN_BROWSER Set to 'false' to disable auto-opening browser (default: true)
148+
76149
EXAMPLES:
77150
./setup.sh setup # Full initial setup
78-
./setup.sh setup-k8s # Setup with Kubernetes support
79-
./setup.sh install-minikube # Install Minikube only
80-
./setup.sh dev # Start development server
81-
./setup.sh db-reset # Reset database
151+
./setup.sh dev # Start dev server with browser
152+
AUTO_OPEN_BROWSER=false ./setup.sh dev # Start without browser
153+
./setup.sh open # Open browser to running server
82154
EOF
83155
}
84156

@@ -806,13 +878,54 @@ start_dev() {
806878

807879
# Run migrations if needed
808880
export DATABASE_URL="$DATABASE_URL"
881+
export REDIS_URL="$REDIS_URL"
882+
809883
if ! sqlx migrate info >/dev/null 2>&1; then
810884
run_migrations
811885
fi
812886

813-
log_info "Starting server at http://localhost:3000"
814-
log_info "API documentation available at http://localhost:3000/api-docs/openapi.json"
815-
cargo run
887+
# Check if we should auto-open browser
888+
local auto_open_browser="${AUTO_OPEN_BROWSER:-true}"
889+
890+
# Start the server in background if auto-opening browser
891+
if [ "$auto_open_browser" = "true" ]; then
892+
log_info "Starting server with auto-browser opening..."
893+
894+
# Start server in background
895+
cargo run &
896+
local server_pid=$!
897+
898+
# Wait for server to be ready and open browser
899+
if wait_and_open_browser 3000 "/auth"; then
900+
log_info "Server is running at http://localhost:3000"
901+
log_info "API documentation available at http://localhost:3000/swagger-ui"
902+
903+
# Wait for the server process
904+
wait $server_pid
905+
else
906+
# Kill the server if browser opening failed
907+
kill $server_pid 2>/dev/null
908+
log_error "Failed to start server properly"
909+
return 1
910+
fi
911+
else
912+
# Normal server start without browser opening
913+
log_info "Starting server at http://localhost:3000"
914+
log_info "API documentation available at http://localhost:3000/swagger-ui"
915+
cargo run
916+
fi
917+
}
918+
# New command to just open browser
919+
open_dev_browser() {
920+
log_info "Opening development browser..."
921+
922+
# Check if server is running
923+
if curl -s -o /dev/null "http://localhost:3000/health" 2>/dev/null; then
924+
open_browser "http://localhost:3000/auth"
925+
else
926+
log_warning "Server is not running. Start it first with: ./setup.sh dev"
927+
return 1
928+
fi
816929
}
817930

818931
build_project() {
@@ -924,6 +1037,10 @@ case "${1:-help}" in
9241037
setup)
9251038
full_setup
9261039
;;
1040+
setup-k8s)
1041+
full_setup
1042+
install_minikube
1043+
;;
9271044
check)
9281045
check_dependencies
9291046
;;
@@ -960,6 +1077,12 @@ case "${1:-help}" in
9601077
dev)
9611078
start_dev
9621079
;;
1080+
dev-no-browser)
1081+
start_dev_no_browser
1082+
;;
1083+
open)
1084+
open_dev_browser
1085+
;;
9631086
build)
9641087
build_project
9651088
;;

src/deployment/models.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ pub struct DeploymentResponse {
9292
pub app_name: String,
9393
pub image: String,
9494
pub status: String,
95-
pub url: String,
95+
pub url: Option<String>,
9696
pub created_at: DateTime<Utc>,
9797
pub message: String,
9898
}

src/handlers/deployment.rs

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -49,38 +49,38 @@ pub async fn create_deployment(
4949
.health_check
5050
.map(|hc| serde_json::to_value(hc))
5151
.transpose()?;
52+
tracing::debug!("Inserting deployment record into database");
5253

5354
sqlx::query!(
54-
r#"
55+
r#"
5556
INSERT INTO deployments (
5657
id, user_id, app_name, image, port, env_vars, replicas,
5758
resources, health_check, status, url, created_at, updated_at,
5859
deployed_at, error_message
5960
)
6061
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
6162
"#,
62-
deployment_id,
63-
user.user_id,
64-
payload.app_name,
65-
payload.image,
66-
payload.port,
67-
env_vars_json,
68-
payload.replicas.unwrap_or(1),
69-
resources,
70-
health_check,
71-
"pending",
72-
url,
73-
now,
74-
now,
75-
Option::<chrono::DateTime<chrono::Utc>>::None, // deployed_at - null initially
76-
None::<String> // error_message
77-
)
78-
.execute(&state.db.pool)
79-
.await?;
80-
81-
println!("Inserted deployment record into database");
82-
63+
deployment_id,
64+
user.user_id,
65+
payload.app_name,
66+
payload.image,
67+
payload.port,
68+
env_vars_json,
69+
payload.replicas.unwrap_or(1),
70+
resources,
71+
health_check,
72+
"pending",
73+
"".to_string(), // url will be set after deployment
74+
now,
75+
now,
76+
Option::<chrono::DateTime<chrono::Utc>>::None, // deployed_at - null initially
77+
None::<String> // error_message
78+
)
79+
.execute(&state.db.pool)
80+
.await?;
81+
tracing::info!("Successfully inserted deployment record into database");
8382
// TODO: Implement Kubernetes deployment logic here
83+
tracing::debug!("Creating deployment job");
8484
let job = DeploymentJob::new(
8585
deployment_id,
8686
user.user_id,
@@ -92,7 +92,7 @@ pub async fn create_deployment(
9292
resources,
9393
health_check,
9494
);
95-
95+
tracing::debug!("Sending job to deployment queue");
9696
if let Err(_) = state.deployment_sender.send(job).await {
9797
// Rollback the database record
9898
let _ = sqlx::query!("DELETE FROM deployments WHERE id = $1", deployment_id)
@@ -101,6 +101,7 @@ pub async fn create_deployment(
101101

102102
return Err(AppError::internal("Failed to queue deployment"));
103103
}
104+
tracing::info!("Deployment system initialized successfully");
104105

105106
// For now, we'll just return the response
106107

@@ -109,7 +110,7 @@ pub async fn create_deployment(
109110
app_name: payload.app_name,
110111
image: payload.image,
111112
status: "pending".to_string(),
112-
url,
113+
url: None,
113114
created_at: now,
114115
message: "Deployment is being processed".to_string(),
115116
}))

0 commit comments

Comments
 (0)