Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored most of the actions #156

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion client/src/components/Auth/AuthenticationResponse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ const decodeFirebaseError = (error: FirebaseError) => {
return "The password or email is incorrect";
case "auth/too-many-requests":
return "Too many requests, please try again later";
case "auth/email-already-in-use":
return "Email already in use";
default:
return "Unknown error";
}
};
}

const decodeCustomError = (error: CustomError) => {
return error.message;
Expand Down
680 changes: 223 additions & 457 deletions server/package-lock.json

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"firebase": "^10.5.0",
"firebase-admin": "^12.0.0",
"geofire-common": "^6.0.0",
"socket.io": "^4.7.4",
Expand Down
9 changes: 3 additions & 6 deletions server/src/actions/createConnectedUser.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
// Uploads a new document in the ConnectedUsers collection.
import { doc, setDoc } from '@firebase/firestore'
import { connectedUsers } from '../utilities/firebaseInit'
import { ConnectedUser } from '../types/User'
import { connectedUsersCollection } from '../utilities/adminInit';

export const createUser = async (connectedUser: ConnectedUser) => {
try {
const ref = doc(connectedUsers, connectedUser.socketId) // Use the socketid as the index
await setDoc(ref, connectedUser)
return true

await connectedUsersCollection.doc(connectedUser.socketId).set(connectedUser)
console.log('User added to the database')
} catch (error) {
console.error(error.message)
return false
Expand Down
6 changes: 2 additions & 4 deletions server/src/actions/createMessage.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// Uploads a new document in the Messages collection.
import { doc, setDoc } from '@firebase/firestore'
import { messages } from '../utilities/firebaseInit'
import { Message } from '../types/Message'
import { messagesCollection } from '../utilities/adminInit'

export const createMessage = async (msg : Message) => {
try {
const ref = doc(messages, msg.msgId)
const status = await setDoc(ref, msg)
await messagesCollection.doc(msg.msgId).set(msg)
return true

} catch (error) {
Expand Down
17 changes: 3 additions & 14 deletions server/src/actions/deleteConnectedUser.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,9 @@
// Delete a ConnectedUser document given a document's index. This should typically be a socketId, but it can also be something else.
import { doc, getDoc, deleteDoc } from '@firebase/firestore'
import { connectedUsers } from '../utilities/firebaseInit'
import { connectedUsersCollection } from '../utilities/adminInit'

export const deleteConnectedUserByIndex = async (index: string) => {
export const deleteConnectedUserByUID = async (socketID: string) => {
try {
const userRef = doc(connectedUsers, index)

// The promise returned by deleteDoc will be fulfilled (aka return 'true') both if the document requested for deletion exists or doesn't exist. It is rejected if the program is unable to send this request to Firestore.
// Therefore, we need to check to see if the document exists first, to most accurately know if it will be deleted.
// However, technically, there could be some kind of failure by deleteDoc after this check is performed, where the status of the deletion would then be inaccurately returned.
// TODO: find a way to assuredly know if a document is deleted after deleteDoc is called.

const userDoc = await getDoc(userRef)
if (!userDoc.exists()) throw Error("[FIREBASE] User does not exist.")

await deleteDoc(userRef)
await connectedUsersCollection.doc(socketID).delete()
return true

} catch (error) {
Expand Down
31 changes: 13 additions & 18 deletions server/src/actions/getConnectedUsers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { doc, endAt, getDocs, orderBy, query, startAt } from 'firebase/firestore'
import { connectedUsers } from '../utilities/firebaseInit'
import { distanceBetween, geohashForLocation, geohashQueryBounds } from 'geofire-common'
import { connectedUsersCollection } from '../utilities/adminInit'

export const findNearbyUsers = async (centerLat: number, centerLon: number, radius: number) => {
// Return an array of nearby userIds (which are also socket ids) given a center latitude and longitude.
Expand All @@ -18,21 +17,21 @@ export const findNearbyUsers = async (centerLat: number, centerLon: number, radi
const promises = []

for (const b of bounds) {
const q = query(
connectedUsers,
orderBy('location.geohash'),
startAt(b[0]),
endAt(b[1])
)

promises.push(getDocs(q))
const q = connectedUsersCollection
.orderBy('location.geohash')
.startAt(b[0])
.endAt(b[1])

promises.push(q.get())
}

// Collect query results and append into a single array
const snapshots = await Promise.all(promises)

const matchingDocs = []

for (const snap of snapshots) {

for (const doc of snap.docs) {
const lat = doc.get('location.lat')
const lon = doc.get('location.lon')
Expand All @@ -42,18 +41,14 @@ export const findNearbyUsers = async (centerLat: number, centerLon: number, radi
const distanceInKm = distanceBetween([lat, lon], [centerLat, centerLon])
const distanceInM = distanceInKm * 1000
if (distanceInM <= radius) {
matchingDocs.push(doc)
matchingDocs.push(doc.get('socketId'))
}
}
}

// Extract userIds from matched documents
const userSocketIds = []
for (const doc of matchingDocs) {
userSocketIds.push(doc.data()['socketId'])
}
console.log(`getNearbyUsers(): ${userSocketIds.length} users found within ${radius} meters of ${centerLat}, ${centerLon}`)
return userSocketIds
console.log(`getNearbyUsers(): ${matchingDocs.length} users found within ${radius} meters of ${centerLat}, ${centerLon}`)
console.log(matchingDocs)
return matchingDocs
} catch (error) {
console.error("getNearbyUsers() failed.", error.message)
}
Expand Down
25 changes: 6 additions & 19 deletions server/src/actions/updateConnectedUser.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,25 @@
import { doc, getDoc, updateDoc } from '@firebase/firestore'
import { connectedUsers } from '../utilities/firebaseInit'
import { geohashForLocation} from 'geofire-common'
import { connectedUsersCollection } from '../utilities/adminInit'

export const toggleUserConnectionStatus = async (index: string) => {
export const toggleUserConnectionStatus = async (socketID: string) => {
try {
const userRef = doc(connectedUsers, index)
const userDoc = await getDoc(userRef)

if (!userDoc.exists()) throw Error("[FIREBASE] User does not exist.")

let status = userDoc.data()['isConnected']

let status = connectedUsersCollection.doc(socketID).isConnected
// Flip the connection status
status = !status

updateDoc(userRef, { isConnected: status })
await connectedUsersCollection.doc(socketID).update({ isConnected: status })
return true

} catch (error) {
console.error(error.message)
return false
}
}

export const updateUserLocation = async (userIndex: string, lat: number, lon: number) => {
export const updateUserLocation = async (socketID: string, lat: number, lon: number) => {
try {
const ref = doc(connectedUsers, userIndex)
const userDoc = await getDoc(ref)

if (!userDoc.exists()) throw Error("[FIREBASE] User does not exist.")

const newHash = geohashForLocation([lat, lon])

updateDoc(ref, { "location.lat": lat, "location.lon": lon, "location.geohash": newHash })
await connectedUsersCollection.doc(socketID).update({ "location.lat": lat, "location.lon": lon, "location.geohash": newHash })
return true
} catch (error) {
console.error(error.message)
Expand Down
28 changes: 11 additions & 17 deletions server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,24 @@
import express from 'express'
import 'dotenv/config'
import 'geofire-common'

import { Message } from './types/Message';

import { createMessage } from './actions/createMessage'
// import { deleteMessageById } from './actions/deleteMessage'
// import { getUserById } from './actions/getUsers'
import { createUser } from './actions/createConnectedUser'
import { toggleUserConnectionStatus, updateUserLocation } from './actions/updateConnectedUser'
import { deleteConnectedUserByIndex } from './actions/deleteConnectedUser'
import { deleteConnectedUserByUID } from './actions/deleteConnectedUser'
import {geohashForLocation} from 'geofire-common';
import { findNearbyUsers } from './actions/getConnectedUsers'
import { ConnectedUser } from './types/User';
import { adminApp } from './utilities/adminInit';


const { createServer } = require('http')
const { Server } = require('socket.io')

adminApp.firestore()


const socket_port = process.env.socket_port
const express_port = process.env.express_port
const app = express()

// Middleware
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

Expand All @@ -39,7 +33,7 @@ const io = new Server(socketServer, {
},
});

io.on('connection', (socket: any) => {
io.on('connection', async (socket: any) => {
console.log(`[WS] User <${socket.id}> connected.`);
const defaultConnectedUser: ConnectedUser = {
uid: "UID",
Expand All @@ -55,12 +49,12 @@ io.on('connection', (socket: any) => {
geohash: "F"
}
} // TODO: Send this info from client on connection
createUser(defaultConnectedUser)
toggleUserConnectionStatus(socket.id)
await createUser(defaultConnectedUser)
await toggleUserConnectionStatus(socket.id)

socket.on('disconnect', () => {
console.log(`[WS] User <${socket.id}> exited.`);
deleteConnectedUserByIndex(socket.id)
deleteConnectedUserByUID(socket.id)
})
socket.on('ping', (ack) => {
// The (ack) parameter stands for "acknowledgement." This function sends a message back to the originating socket.
Expand Down Expand Up @@ -103,11 +97,11 @@ io.on('connection', (socket: any) => {
console.error("[WS] Error sending message:", error.message)
}
})
socket.on('updateLocation', async (message, ack) => {
socket.on('updateLocation', async (location, ack) => {
console.log(`[WS] Recieved new location from user <${socket.id}>.`)
try {
const lat = Number(message.lat)
const lon = Number(message.lon)
const lat = Number(location.lat)
const lon = Number(location.lon)
const success = await updateUserLocation(socket.id, lat, lon)
if (success) {
console.log("[WS] Location updated in database successfully.")
Expand Down Expand Up @@ -217,7 +211,7 @@ app.delete('/users', async (req, res) => {
const userId = req.query.userId
if (typeof userId != "string") throw Error(" [userId] is not a string.")

const success = await deleteConnectedUserByIndex(userId)
const success = await deleteConnectedUserByUID(userId)
if (!success) throw Error(" deleteUserById() failed.")

console.log(`[EXP] Request <DELETE /users${query}> returned successfully.`)
Expand Down
13 changes: 13 additions & 0 deletions server/src/private_key/private.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"type": "service_account",
"project_id": "fir-auth-89462",
"private_key_id": "770edc7187f5ef3d35359b9ad2304570d4f170ff",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDCS6oM6wYwCp7a\nCXauPpBDjLzqq5PrMZCWOoi2THjqTzLJQc/Xwg5XlOyRX1DB4Uzl1iutfLsQXNuv\nMRze3i2jIOLysnrkvSuLW9n19k/1gIYYm7oxZQPaJ5iNJ33GFiNJqULlmMTvv6vp\nhXOOUZxl9dNY3HRpICcaGNPXjAv3tG7W+iHsidphp88Q8OMMmkZcl3+h2Hc1yDEf\nmXPR0YynfakDi45tMf5F9x3jRT6y6O30PSpZUIVL2cfwWs+zojnK+vy+cGCjBIJE\n/uI+A7XJJ4BWNLH/jhy6Jta/jDkCj/JbUsxRTX2ZuUeVi8uSMkzdy/Pb+o5f4SaJ\nl3mTa7S5AgMBAAECggEAEIChdwMrxX8TbrC81TAga/JbVeHAmKp/LblXRQeSAhG7\nvisSMpDLi84M+UxzlSIUGFXkZBH65/kBGjxVR8subGN1zzgQVtcH6KhipwDWmgMi\ncJriecFLDleMXhnXdZCKCv6+vTZIbNYWbYlNjy4YlvLmEm84DnlCBPYMoStGlXFm\nRKEfLl4FHHmCRcRkuGWRyKk9LtKNykrlaFVZ3BL11/TC38BlK3us+1cyUO3dA1EW\njAYSRG3tAVGVS7VUoxDDcA1V+Wnccpt+ws/rzIVYcTXawXrpHXFx977FwarGHReL\nmRmjHYGo/4Ry+q8Nk1y7GkdPYxq5GVAtXuRqSx7EgQKBgQD86ru/bBxJZxNAuHTE\nx9j/n0MrH9ulAFEzAXzq12Yf2xSytrUbD31zPg+rrFTGDNYISUPKSa9sxpC/jiwB\nXmuNhFVvt1521naZOtyezo3RYztcwOIxscvULHMUt/ikaFVsytlxrqDn0MJXuKM/\n5OZbbolc5pR3Oi82FOz09xB+OQKBgQDEqf5ox6V8ZfrMdFvhKC0EklyfDjClrJa2\nCkE0HK9ePxCpnEqBYC8wj6pXNOnLONYNZIjJ7Nz2CiFd0gIt7Ep9KtDNve99dWHR\nObPbt9fC8vMuzotBN6P345hzdqXR7OUUfAPFBCZTysWrfHzqg1tFYkt5t+YVfWuu\nMRq/xpzqgQKBgQC00Af7eQnb/EHKYlSwngNn9G8rtHHty4VBhs3MgsOzAIgSoAZn\n2zIfon3HiMNud5zIfcBmLTmp9WdkWvrg26Tenn4KCTkSko5lS6yQKDFBQcUdsZPE\nXUzQWhrH9CJhP2nbBkZgPK0yLY/S8OBc/IMnWKYBcaMwfbtk2Z7yHnN/GQKBgClH\ndTsRDM87qJTZp59vC2P2RLKuC8/6lffH1z/U9YpWumyffZQCWGVdAmgjlx8s4uEU\nxRF9QjPylGZY+lQhUNFM9174CxjOVqXP8syfng4xaJHekKQzxZr2jr1NniieDMdr\n8G6eHF1iJnOEQcQHplS9+RGnZAgGt19styyhx7YBAoGBAN++OfEq6S8zW/+Q9E8x\nAxvdNrFOkHnJf+URwTZQNFebvRUDouYjHE1fOCSM7npkNFV/DyINTsP6cNGKwGXM\nox1ODGb2uLk3hEQLDbqocIoWnuzY2QU3lubrSdAnEUDBovjd4of47BwYo2HfA+Pu\nTuLU4vtbFvSH7e3OJ9A//cKD\n-----END PRIVATE KEY-----\n",
"client_email": "[email protected]",
"client_id": "102183968562626917121",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-f0nzi%40fir-auth-89462.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}
9 changes: 6 additions & 3 deletions server/src/utilities/adminInit.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
const { initializeApp } = require('firebase-admin/app');
const admin = require('firebase-admin');
const serviceAccount = require("../../src/private_key/<YOUR KEY>.json");
const serviceAccount = require("../../src/private_key/private.json");

export const adminApp = admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
credential: admin.credential.cert(serviceAccount),
});

export const db = admin.firestore();
export const connectedUsersCollection = db.collection('users');
export const messagesCollection = db.collection('messages');

console.log("[FIREBASE-ADMIN] Firebase admin SDK synced.")
28 changes: 0 additions & 28 deletions server/src/utilities/firebaseInit.ts

This file was deleted.