164 lines
6.2 KiB
JavaScript
164 lines
6.2 KiB
JavaScript
import readline from 'readline';
|
|
import { io } from 'socket.io-client';
|
|
|
|
const API_URL = process.env.API_URL || 'http://localhost:4010';
|
|
const TENANT_ID = 'tripz'; // Change this if you have a different slug
|
|
|
|
const rl = readline.createInterface({
|
|
input: process.stdin,
|
|
output: process.stdout
|
|
});
|
|
|
|
const ask = (query) => new Promise((resolve) => rl.question(query, resolve));
|
|
|
|
// --- API Helpers ---
|
|
async function api(method, path, body = null, token = null) {
|
|
const headers = {
|
|
'Content-Type': 'application/json',
|
|
'x-tenant-id': TENANT_ID,
|
|
'x-device-id': 'simulated-device-123'
|
|
};
|
|
if (token) headers['Authorization'] = `Bearer ${token}`;
|
|
|
|
const options = { method, headers };
|
|
if (body) options.body = JSON.stringify(body);
|
|
|
|
const res = await fetch(`${API_URL}${path}`, options);
|
|
const data = await res.json().catch(() => null);
|
|
|
|
if (!res.ok) {
|
|
console.error(`\x1b[31m[API Error] ${method} ${path} -> ${res.status}\x1b[0m`, data);
|
|
throw new Error(`API Error: ${res.status}`);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
// --- Main Simulation ---
|
|
async function run() {
|
|
console.log('\n\x1b[36m==========================================');
|
|
console.log('🚀 Tripz Backend Live Simulation Engine');
|
|
console.log('==========================================\x1b[0m\n');
|
|
|
|
// 1. Authentication
|
|
const driverPhone = await ask('📞 Enter Driver Phone Number (e.g. +962791234567): ');
|
|
console.log(`[Driver] Requesting OTP for ${driverPhone}...`);
|
|
await api('POST', '/auth/send-otp', { phone: driverPhone });
|
|
|
|
const driverOtp = await ask(`🔑 Enter OTP received by Driver ${driverPhone}: `);
|
|
const driverAuth = await api('POST', '/auth/verify-otp', { phone: driverPhone, code: driverOtp });
|
|
const driverToken = driverAuth.access_token;
|
|
console.log('\x1b[32m[Driver] Authenticated successfully!\x1b[0m');
|
|
|
|
const riderPhone = await ask('\n📞 Enter Rider Phone Number (e.g. +962781234567): ');
|
|
console.log(`[Rider] Requesting OTP for ${riderPhone}...`);
|
|
await api('POST', '/auth/send-otp', { phone: riderPhone });
|
|
|
|
const riderOtp = await ask(`🔑 Enter OTP received by Rider ${riderPhone}: `);
|
|
const riderAuth = await api('POST', '/auth/verify-otp', { phone: riderPhone, code: riderOtp });
|
|
const riderToken = riderAuth.access_token;
|
|
console.log('\x1b[32m[Rider] Authenticated successfully!\x1b[0m\n');
|
|
|
|
// 2. Setup Driver Profile & Go Online
|
|
console.log(`[Driver] Creating Driver profile...`);
|
|
await api('POST', '/drivers/apply', { service_class: 'economy', vehicle_make: 'Toyota', vehicle_model: 'Prius', vehicle_plate: '12-3456' }, driverToken);
|
|
|
|
console.log(`[Driver] Going Online...`);
|
|
await api('PATCH', '/drivers/status', { online: true }, driverToken);
|
|
console.log('\x1b[32m[Driver] Profile created and is now ONLINE.\x1b[0m\n');
|
|
|
|
// 3. Connect WebSockets
|
|
console.log(`[Sockets] Connecting Rider and Driver via WebSockets...`);
|
|
const driverSocket = io(API_URL, { extraHeaders: { Authorization: `Bearer ${driverToken}` } });
|
|
const riderSocket = io(API_URL, { extraHeaders: { Authorization: `Bearer ${riderToken}` } });
|
|
|
|
let tripId = null;
|
|
|
|
driverSocket.on('connect', () => console.log('\x1b[36m[Driver WS] Connected to Gateway\x1b[0m'));
|
|
riderSocket.on('connect', () => console.log('\x1b[36m[Rider WS] Connected to Gateway\x1b[0m'));
|
|
|
|
driverSocket.on('trip:dispatch', async (data) => {
|
|
console.log(`\n\x1b[35m[Driver WS] 🔔 RECEIVED DISPATCH for Trip ${data.id}!\x1b[0m`);
|
|
tripId = data.id;
|
|
|
|
console.log(`[Driver] Accepting Trip ${tripId}...`);
|
|
await api('POST', `/trips/${tripId}/accept`, null, driverToken);
|
|
console.log('\x1b[32m[Driver] Trip Accepted!\x1b[0m');
|
|
|
|
// Join Trip Room
|
|
driverSocket.emit('trip:join', { tripId });
|
|
riderSocket.emit('trip:join', { tripId });
|
|
console.log(`[Sockets] Both joined trip room: ${tripId}\n`);
|
|
});
|
|
|
|
riderSocket.on('trip:status_changed', (data) => {
|
|
console.log(`\x1b[33m[Rider WS] Trip Status Changed -> ${data.status}\x1b[0m`);
|
|
});
|
|
|
|
// 4. Driver Location Pings
|
|
let driverLat = 32.0645; // Zarqa Coordinates
|
|
let driverLng = 36.0827;
|
|
|
|
const locationInterval = setInterval(() => {
|
|
// Driver moves slightly
|
|
driverLat += 0.0001;
|
|
driverSocket.emit('driver:location', { lat: driverLat, lng: driverLng, speed: 40, heading: 90 });
|
|
console.log(`[Driver WS] 📍 Location ping: ${driverLat.toFixed(5)}, ${driverLng.toFixed(5)}`);
|
|
}, 3000);
|
|
|
|
// Wait a few seconds before Rider requests
|
|
await new Promise(r => setTimeout(r, 5000));
|
|
|
|
// 5. Rider Requests Trip
|
|
console.log(`\n[Rider] Requesting Trip from Zarqa...`);
|
|
const tripRequest = await api('POST', '/trips', {
|
|
city: 'amman',
|
|
service_class: 'economy',
|
|
origin: { lat: 32.0650, lng: 36.0830 }, // Zarqa origin
|
|
destination: { lat: 32.0700, lng: 36.0900 }
|
|
}, riderToken);
|
|
|
|
console.log(`\x1b[32m[Rider] Trip created: ${tripRequest.id}\x1b[0m`);
|
|
|
|
// 6. Simulate Trip Flow (Wait 10 seconds per state)
|
|
await new Promise(r => setTimeout(r, 10000));
|
|
|
|
if (tripId) {
|
|
console.log(`\n[Driver] Arriving at pickup...`);
|
|
await api('PATCH', `/trips/${tripId}/status`, { status: 'driver_arrived' }, driverToken);
|
|
|
|
await new Promise(r => setTimeout(r, 5000));
|
|
|
|
console.log(`\n[Driver] Starting Trip...`);
|
|
await api('PATCH', `/trips/${tripId}/status`, { status: 'in_progress' }, driverToken);
|
|
|
|
console.log(`\n[System] Simulating 1-minute ride to destination...`);
|
|
// Simulate 30 seconds wait
|
|
await new Promise(r => setTimeout(r, 30000));
|
|
console.log(`[System] Halfway there...`);
|
|
await new Promise(r => setTimeout(r, 30000));
|
|
|
|
console.log(`\n[Driver] Completing Trip...`);
|
|
await api('PATCH', `/trips/${tripId}/status`, { status: 'completed' }, driverToken);
|
|
|
|
await new Promise(r => setTimeout(r, 2000));
|
|
|
|
console.log(`\n[Driver] Collecting Cash...`);
|
|
await api('PATCH', `/trips/${tripId}/status`, { status: 'paid' }, driverToken);
|
|
|
|
console.log('\n\x1b[32m🎉 Simulation Completed Successfully! 🎉\x1b[0m\n');
|
|
} else {
|
|
console.log('\n\x1b[31mFailed to receive dispatch!\x1b[0m');
|
|
}
|
|
|
|
// Cleanup
|
|
clearInterval(locationInterval);
|
|
driverSocket.disconnect();
|
|
riderSocket.disconnect();
|
|
rl.close();
|
|
}
|
|
|
|
run().catch(err => {
|
|
console.error('\x1b[31mSimulation Failed!\x1b[0m', err);
|
|
process.exit(1);
|
|
});
|