Skip to content

Commit

Permalink
refactor(backend and frontend): Made some small refactors, added in b…
Browse files Browse the repository at this point in the history
…etter comments, removed some duplication, hope this doesn't break anything! [2024-11-01]
  • Loading branch information
CHRISCARLON committed Nov 1, 2024
1 parent a5151b8 commit ea67896
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 39 deletions.
54 changes: 28 additions & 26 deletions gridwalk-backend/src/routes/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,28 @@ pub async fn upload_layer(
headers: HeaderMap,
mut multipart: Multipart,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
// Extract chunk information
let chunk_number = headers
.get("x-chunk-number")
// Extract chunk information sent front frontend
// Total chunks to be processed
let total_chunks = headers
.get("x-total-chunks")
.and_then(|v| v.to_str().ok())
.and_then(|v| v.parse::<u32>().ok())
.ok_or_else(|| {
let error = json!({ "error": "Missing or invalid chunk number" });
let error = json!({ "error": "Missing or invalid total chunks" });
(StatusCode::BAD_REQUEST, Json(error))
})?;

let total_chunks = headers
.get("x-total-chunks")
// The current chunk number in the stream
let chunk_number = headers
.get("x-chunk-number")
.and_then(|v| v.to_str().ok())
.and_then(|v| v.parse::<u32>().ok())
.ok_or_else(|| {
let error = json!({ "error": "Missing or invalid total chunks" });
let error = json!({ "error": "Missing or invalid chunk number" });
(StatusCode::BAD_REQUEST, Json(error))
})?;

// Get workspace id from frontend
let workspace_id = headers
.get("x-workspace-id")
.and_then(|v| v.to_str().ok())
Expand All @@ -51,6 +54,7 @@ pub async fn upload_layer(
(StatusCode::BAD_REQUEST, Json(error))
})?;

// Ensure that the user has auth to upload layer
let user = auth_user.user.as_ref().ok_or_else(|| {
let error = json!({
"error": "Unauthorized request",
Expand All @@ -59,6 +63,7 @@ pub async fn upload_layer(
(StatusCode::UNAUTHORIZED, Json(error))
})?;

// Create layer info (layer name and workspace id holder) + holder for final file path
let mut layer_info: Option<CreateLayer> = None;
let mut file_path = None;

Expand All @@ -72,16 +77,21 @@ pub async fn upload_layer(
(StatusCode::INTERNAL_SERVER_ERROR, Json(error))
})?;

// Create upload id - which is the workspace id that is sent through
// This is what is used to create the temp file path
// "temp_{upload_id}_{filename}"
// this is only temporary to ensure that the chunks are appended to the same temp file
let upload_id = format!("{}_upload", workspace_id);

// Logging info
tracing::info!(
"Processing request: chunk {}/{}, upload_id: {}",
chunk_number,
total_chunks,
upload_id
);

// Process multipart form
// Process multipart form starting point
while let Some(mut field) = multipart.next_field().await.map_err(|e| {
let error = json!({
"error": "Failed to process form field",
Expand Down Expand Up @@ -150,6 +160,7 @@ pub async fn upload_layer(
);

if chunk_number < total_chunks - 1 {
tracing::info!("Non-final chunk processed, awaiting more chunks");
let upload_id = if chunk_number == 0 {
temp_path
.file_name()
Expand All @@ -171,7 +182,7 @@ pub async fn upload_layer(
})),
));
}

tracing::info!("Final chunk received, processing complete file");
file_path = Some(temp_path);
}
}
Expand Down Expand Up @@ -210,6 +221,10 @@ pub async fn upload_layer(
}

// Get final path and layer info
// At this point, we know:
// 1. We have processed the final chunk (checked during file processing)
// 2. We have a complete file and temp file path
// 3. We can proceed with final processing to PostGIS
let final_path = file_path.ok_or_else(|| {
let error = json!({
"error": "No file was uploaded",
Expand All @@ -218,20 +233,6 @@ pub async fn upload_layer(
(StatusCode::BAD_REQUEST, Json(error))
})?;

// If this is not the final chunk, return progress
if chunk_number < total_chunks - 1 {
return Ok((
StatusCode::OK,
Json(json!({
"status": "chunk_received",
"chunk": chunk_number,
"total": total_chunks,
"upload_id": final_path.file_name().unwrap().to_string_lossy()
})),
));
}

// Only process the complete file on the final chunk
let layer_info = layer_info.ok_or_else(|| {
let error = json!({
"error": "No layer info provided",
Expand All @@ -250,7 +251,7 @@ pub async fn upload_layer(
"Failed to clean up file after successful upload: {}",
cleanup_err
);
// Continue with success response even if cleanup fails
// Continue with success response even if cleanup fails - NEED TO CHANGE THIS
} else {
tracing::info!(
"Successfully cleaned up temporary file: {}",
Expand Down Expand Up @@ -285,6 +286,7 @@ async fn process_layer(
(StatusCode::NOT_FOUND, Json(error))
})?;

// Get workspace member
let member = workspace
.get_member(&state.app_data, user)
.await
Expand All @@ -304,7 +306,7 @@ async fn process_layer(
return Err((StatusCode::FORBIDDEN, Json(error)));
}

// Create layer in database
// Check permissions - WE NEED TO RENAME THIS TO SOMETHING OTHER THAN CREATE
layer
.create(&state.app_data, user, &workspace)
.await
Expand All @@ -328,7 +330,7 @@ async fn process_layer(
(StatusCode::INTERNAL_SERVER_ERROR, Json(error))
})?;

// Write the record to database
// Write the record to database (e.g. DynamoDB)
layer.write_record(&state.app_data).await.map_err(|e| {
let error = json!({
"error": "Failed to write layer record to Database",
Expand Down
6 changes: 3 additions & 3 deletions gridwalk-ui/src/app/api/upload/layer/route.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NextRequest } from "next/server";
import { LayerInfo, FileConfigs } from "./types";

const HARDCODED_AUTH_TOKEN = "VVPME0BYEDG7LJYGLL9PKJ8AS1GABM";
const DETAILS = "VVPME0BYEDG7LJYGLL9PKJ8AS1GABM";

interface ChunkInfo {
currentChunk: number;
Expand Down Expand Up @@ -121,7 +121,7 @@ export async function POST(request: NextRequest) {
);

const headers: HeadersInit = {
Authorization: `Bearer ${HARDCODED_AUTH_TOKEN}`,
Authorization: `Bearer ${DETAILS}`,
Accept: "application/json",
"X-File-Type": "." + (file as File).name.split(".").pop()?.toLowerCase(),
"X-Original-Content-Type": originalType || contentType,
Expand Down Expand Up @@ -157,7 +157,7 @@ export async function POST(request: NextRequest) {
return Response.json({
success: true,
data,
chunkInfo, // Include chunk info in response if present
chunkInfo,
});
} catch (error) {
console.error("Upload error:", {
Expand Down
17 changes: 7 additions & 10 deletions gridwalk-ui/src/app/project/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"use client";

import React, { useState, useCallback } from "react";
import { useMapInit } from "./components/mapInit/mapInit";
import MainMapNavigation from "./components/navBars/mainMapNavigation";
Expand All @@ -11,7 +10,6 @@ import {
BaseEditNav,
} from "./components/navBars/types";

// Enhanced type definitions
export interface LayerUpload {
id: string;
name: string;
Expand Down Expand Up @@ -40,7 +38,6 @@ export interface UploadProgress {
percentage: number;
}

// Constants remain the same
const MAP_STYLES = {
light: "/OS_VTS_3857_Light.json",
dark: "/OS_VTS_3857_Dark.json",
Expand All @@ -55,10 +52,10 @@ const INITIAL_MAP_CONFIG = {
} as const;

const DEFAULT_WORKSPACE = "d068ebc4-dc32-4929-ac55-869e04bfb269" as const;
const CHUNK_SIZE = 5 * 1024 * 1024; // 5MB chunks
const CHUNK_SIZE = 5 * 1024 * 1024;

export default function Project() {
// Previous state remains
// STATES
const [selectedItem, setSelectedItem] = useState<MainMapNav | null>(null);
const [selectedEditItem, setSelectedEditItem] = useState<MapEditNav | null>(
null,
Expand All @@ -72,15 +69,15 @@ export default function Project() {
const [uploadSuccess, setUploadSuccess] = useState(false);
const [isUploading, setIsUploading] = useState(false);
const [error, setError] = useState<string | null>(null);

// New state for upload progress
const [uploadProgress, setUploadProgress] = useState<number>(0);

// MAP CONFIG
const { mapContainer, mapError } = useMapInit({
...INITIAL_MAP_CONFIG,
styleUrl: currentStyle,
});

// HANDLE UPLOAD
const handleLayerUpload = useCallback(
async (
file: File,
Expand Down Expand Up @@ -126,12 +123,13 @@ export default function Project() {
const progress = Math.round(((currentChunk + 1) / totalChunks) * 100);
setUploadProgress(progress);

// If this was the last chunk and successful
// If this was the last chunk
// Finish chunk upload
if (currentChunk === totalChunks - 1) {
setUploadSuccess(true);
setTimeout(() => {
setUploadSuccess(false);
setUploadProgress(0); // Reset progress
setUploadProgress(0);
}, 3000);
}
}
Expand All @@ -148,7 +146,6 @@ export default function Project() {
[],
);

// Other handlers remain the same
const handleLayerDelete = useCallback((layerId: string) => {
setLayers((prev) => prev.filter((layer) => layer.id !== layerId));
}, []);
Expand Down

0 comments on commit ea67896

Please sign in to comment.