initial commit
This commit is contained in:
198
app/api/services/deploy-cloude/route.ts
Normal file
198
app/api/services/deploy-cloude/route.ts
Normal file
@@ -0,0 +1,198 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { authMiddleware } from '@/lib/auth-middleware'
|
||||
import connectDB from '@/lib/mongodb'
|
||||
import { User as UserModel } from '@/models/user'
|
||||
import BillingService from '@/lib/billing-service'
|
||||
import { checkServiceAvailability } from '@/lib/system-settings'
|
||||
|
||||
// VPC subnet mapping based on datacenter
|
||||
const VPC_SUBNET_MAP: { [key: string]: string } = {
|
||||
inmumbaizone2: '3889f7ca-ca19-4851-abc7-5c6b4798b3fe', // Mumbai public subnet
|
||||
inbangalore: 'c17032c9-3cfd-4028-8f2a-f3f5aa8c2976', // Bangalore public subnet
|
||||
innoida: '95c60b59-4925-4b7e-bd05-afbf940d8000', // Delhi/Noida public subnet
|
||||
defra1: '72ea201d-e1e7-4d30-a186-bc709efafad8', // Frankfurt public subnet
|
||||
uslosangeles: '0e253cd1-8ecc-4b65-ae0f-6acbc53b0fb6', // Los Angeles public subnet
|
||||
inbangalore3: 'f687a58b-04f0-4ebe-b583-65788a1d18bf', // Bangalore DC3 public subnet
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
// Check if VPS deployment service is enabled
|
||||
if (!(await checkServiceAvailability('vps'))) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
status: 'error',
|
||||
message: 'VPS deployment service is currently disabled by administrator',
|
||||
},
|
||||
{ status: 503 }
|
||||
)
|
||||
}
|
||||
|
||||
// Check authentication using your auth middleware
|
||||
const user = await authMiddleware(request)
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ status: 'error', message: 'Unauthorized: Please login to continue' },
|
||||
{ status: 401 }
|
||||
)
|
||||
}
|
||||
|
||||
// Get input data from request
|
||||
const input = await request.json()
|
||||
if (!input) {
|
||||
return NextResponse.json({ status: 'error', message: 'Invalid JSON' }, { status: 400 })
|
||||
}
|
||||
|
||||
// Get API key from environment
|
||||
const UTHO_API_KEY = process.env.UTHO_API_KEY
|
||||
if (!UTHO_API_KEY) {
|
||||
return NextResponse.json(
|
||||
{ status: 'error', message: 'API configuration missing' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
|
||||
// Connect to MongoDB
|
||||
await connectDB()
|
||||
|
||||
// Get user data for billing
|
||||
const userData = await UserModel.findOne({ email: user.email })
|
||||
if (!userData) {
|
||||
return NextResponse.json({ status: 'error', message: 'User not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
const requiredAmount = input.amount || 0
|
||||
|
||||
// Check balance only if amount > 0 (some services might be free)
|
||||
if (requiredAmount > 0) {
|
||||
const currentBalance = userData.balance || 0
|
||||
if (currentBalance < requiredAmount) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
status: 'error',
|
||||
message: `Insufficient balance. Required: ₹${requiredAmount}, Available: ₹${currentBalance}`,
|
||||
code: 'INSUFFICIENT_BALANCE',
|
||||
},
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Get VPC subnet based on datacenter
|
||||
const vpcSubnet = VPC_SUBNET_MAP[input.dclocation] || VPC_SUBNET_MAP['inbangalore']
|
||||
|
||||
// Prepare Utho payload - use the exact format from your PHP code
|
||||
const uthoPayload = {
|
||||
dcslug: input.dclocation,
|
||||
planid: input.planid,
|
||||
billingcycle: 'hourly',
|
||||
auth: 'option2',
|
||||
enable_publicip: input.publicip !== false,
|
||||
subnetRequired: false,
|
||||
firewall: '23434645',
|
||||
cpumodel: 'intel',
|
||||
enablebackup: input.backup || false,
|
||||
root_password: input.password,
|
||||
support: 'unmanaged',
|
||||
vpc: vpcSubnet,
|
||||
cloud: [
|
||||
{
|
||||
hostname: input.hostname,
|
||||
},
|
||||
],
|
||||
image: input.image,
|
||||
sshkeys: '',
|
||||
}
|
||||
|
||||
console.log('Sending to Utho API:', uthoPayload)
|
||||
|
||||
// Make API request to Utho
|
||||
const UTHO_API_URL = 'https://api.utho.com/v2/cloud/deploy'
|
||||
const response = await fetch(UTHO_API_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${UTHO_API_KEY}`,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: '*/*',
|
||||
},
|
||||
body: JSON.stringify(uthoPayload),
|
||||
})
|
||||
|
||||
const httpCode = response.status
|
||||
const deploymentSuccess = httpCode >= 200 && httpCode < 300
|
||||
const responseData = await response.json()
|
||||
|
||||
// Add status field like PHP does
|
||||
responseData.status = deploymentSuccess ? 'success' : 'error'
|
||||
|
||||
console.log('Utho API response:', { httpCode, responseData })
|
||||
|
||||
// Process billing using the new comprehensive billing service
|
||||
try {
|
||||
const billingResult = await BillingService.processServiceDeployment({
|
||||
user: {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
siliconId: userData.siliconId,
|
||||
},
|
||||
service: {
|
||||
name: 'VPS Server',
|
||||
type: 'vps',
|
||||
id: responseData.server_id || responseData.id,
|
||||
instanceId: responseData.server_id || responseData.id,
|
||||
config: {
|
||||
hostname: input.hostname,
|
||||
planid: input.planid,
|
||||
dclocation: input.dclocation,
|
||||
image: input.image,
|
||||
backup: input.backup,
|
||||
publicip: input.publicip,
|
||||
},
|
||||
},
|
||||
amount: requiredAmount,
|
||||
currency: 'INR',
|
||||
cycle: (input.cycle as any) || 'onetime',
|
||||
deploymentSuccess,
|
||||
deploymentResponse: responseData,
|
||||
metadata: {
|
||||
userAgent: request.headers.get('user-agent'),
|
||||
ip: request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip'),
|
||||
uthoPayload,
|
||||
httpCode,
|
||||
},
|
||||
})
|
||||
|
||||
console.log('Billing processed:', {
|
||||
billingId: billingResult.billing.billing_id,
|
||||
transactionId: billingResult.transaction?.transactionId,
|
||||
balanceUpdated: billingResult.balanceUpdated,
|
||||
})
|
||||
} catch (billingError) {
|
||||
console.error('Billing processing failed:', billingError)
|
||||
// Continue even if billing fails, but return error if it's balance-related
|
||||
if (billingError instanceof Error && billingError.message.includes('Insufficient balance')) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
status: 'error',
|
||||
message: billingError.message,
|
||||
code: 'INSUFFICIENT_BALANCE',
|
||||
},
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Return the exact same response format as PHP
|
||||
return NextResponse.json(responseData, { status: httpCode })
|
||||
} catch (error) {
|
||||
console.error('Cloud deployment error:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
status: 'error',
|
||||
message: 'Internal server error',
|
||||
details: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user