other/train-to-cloud-city/devices/rfid/utils/firestoreHelpers.js (178 lines of code) (raw):

// Copyright 2024 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. const { firebase, db, app, firestore } = require("./firebase.js"); const { StringDecoder } = require("node:string_decoder"); const { getMotor } = require("./train.js"); const { queueMessageToPublish } = require("./metrics.js"); /** * setMissionPattern * ---------------------- */ async function setMissionPattern(chunk, reader) { const motor = await getMotor(); const matchingTag = await getMatchingTag({ chunk }); const proposalRef = db.collection("global").doc("proposal"); const mailboxRef = db.collection("global").doc("input_mailbox"); /** * PATTERNS TO SELECT FROM * high complex - 3300348D69E3 * medium complex - 33003558732D * low complex - 0D0088F32B5D */ if (matchingTag?.pattern_slug) { try { await proposalRef.set( { pattern_slug: matchingTag?.pattern_slug }, { merge: false }, ); queueMessageToPublish("mission-selected", { chunk, pattern_slug: matchingTag?.pattern_slug, }); console.log( `Mission has been read: ${JSON.stringify(matchingTag?.pattern_slug)}. Waiting for event input trigger.`, ); } catch (error) { console.error(error); } return; } /** * EVENT RFID TAG (let's go magic wand) * check-pattern (GO) - 0D00876E4DA9 * stop 330034B6B607 * reset - 330035D3B96C */ if (matchingTag?.event_slug) { const { event_slug } = matchingTag; if (event_slug === "check-pattern") { console.log("Checking pattern ...."); queueMessageToPublish("begin-game", { pattern_slug: matchingTag?.pattern_slug, }); try { await mailboxRef.set({ input: "check_pattern" }); motor?.setPower(25); // move towards station console.log( `Input mailbox has been triggered to check pattern and now moving to station.`, ); } catch (error) { motor?.stop(); console.error(error); } } if (event_slug === "reset") { console.log("Admin reset registered."); try { motor?.stop(); await mailboxRef.set({ input: "reset" }); motor?.setPower(25); } catch (error) { console.error(error); } } if (event_slug === "stop") { console.log("Admin stop registered."); motor?.stop(); } } } /** * getMatchingTag * ---------------------- * Fetches GCP services, mission patterns, event tags (i.e eval trigger tag) */ async function getMatchingTag(id) { const tagRef = db.collection("tags"); let tag = {}; try { const snapshot = await tagRef.get(); snapshot.docs.forEach((doc) => { const data = doc.data(); const chunk = new String(id?.chunk); const docId = new String(doc.id); if (chunk.includes(docId)) { tag = data; } }); } catch (error) { console.error(error); } return tag; } /** * getTrain * ---------------------- */ async function getTrain() { const trainRef = db.collection("global").doc("train"); let doc = {}; try { const snapshot = await trainRef.get(); doc = snapshot.data(); } catch (error) { console.error(error); } return doc; } /** * getTrainMailbox * ---------------------- */ async function getTrainMailbox() { const trainRef = db.collection("global").doc("train_mailbox"); let doc = {}; try { const snapshot = await trainRef.get(); doc = snapshot.data(); } catch (error) { console.error(error); } return doc; } /** * clearTrainMailbox * ---------------------- */ async function clearTrainMailbox() { const ref = db.collection("global").doc("train_mailbox"); try { await ref.update({ input: null }, { merge: true }); console.log(`Train mailbox cleared`); } catch (error) { console.error(error); } } /** * matchCargoToServices *------------------- * chunks -> rfid tag id */ async function matchCargoToServices(chunks) { let cargos = []; for (const chunk of chunks) { const buffer = Buffer.from(JSON.stringify({ chunk })); const id = JSON.parse(buffer.toString()); // Match read rfid chunk with correct service const matchingService = await getMatchingTag(id); if (matchingService?.slug) { cargos.push(matchingService.slug); } } return cargos; } /** * submitActualCargo *------------------- * chunks -> rfid tag id */ async function submitActualCargo(chunks) { let cargos = await matchCargoToServices(chunks); // Updates actual_cargo state with newly read service const ref = db.collection("global").doc("cargo"); try { await ref.update({ actual_cargo: cargos }, { merge: true }); queueMessageToPublish("cargo-read", { actualCargo: cargos, timestamp: Date.now(), }); console.log(`Cargos read ${JSON.stringify(cargos)}`); } catch (error) { console.error(error); } } /** * updateLocation *------------------- */ async function updateLocation(location) { const ref = db.collection("global").doc("train"); try { await ref.update({ actual_location: location }, { merge: true }); queueMessageToPublish("location-updated", { location }); console.log(`Passed checkpoint ${location}`); } catch (error) { console.error(error); } } /** * updateInputMailbox *------------------- * index -> step train is on */ async function updateInputMailbox(eventString) { const ref = db.collection("global").doc("input_mailbox"); try { await ref.update({ input: eventString }, { merge: true }); } catch (error) { console.error(error); } } /** * trainMailboxListener * ---------------------- */ async function trainMailboxListener(cb = () => {}) { const trainRef = db.collection("global").doc("train_mailbox"); trainRef.onSnapshot(cb); } /** * signalListener * ---------------------- */ async function signalListener(cb = () => {}) { const signalRef = db.collection("global").doc("signals"); signalRef.onSnapshot(cb); } /** * proposalListener * ---------------------- */ async function proposalListener(cb = () => {}) { const proposalRef = db.collection("global").doc("proposal"); proposalRef.onSnapshot(cb); } module.exports = { getTrain, getTrainMailbox, trainMailboxListener, proposalListener, signalListener, setMissionPattern, updateLocation, updateInputMailbox, submitActualCargo, clearTrainMailbox, };