Skip to content
Snippets Groups Projects
Commit 3e302fca authored by Jack Hu's avatar Jack Hu
Browse files

init

parents
No related branches found
No related tags found
No related merge requests found
.env 0 → 100644
# AWS RDS
RDS_HOSTNAME=
RDS_USERNAME=
RDS_PASSWORD=
RDS_PORT=
RDS_DATABASE=
# AWS DYNAMODB
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
\ No newline at end of file
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
.fleet/*
# Elastic Beanstalk Files
.elasticbeanstalk/*
!.elasticbeanstalk/*.cfg.yml
!.elasticbeanstalk/*.global.yml
# Lab 1 Skeleton
## Getting started
You'll need to put the following in your .env (keep in mind, never commit this in normal circumstances, and you can delete it from your repo once the file is on your EC2 instance):
```
# AWS RDS
RDS_HOSTNAME=<your rds hostname>
RDS_USERNAME=<your rds username>
RDS_PASSWORD=<your rds password>
RDS_PORT=<your rds port>
# AWS DYNAMODB
AWS_ACCESS_KEY_ID=<your rds access key id>
AWS_SECRET_ACCESS_KEY=<your rds secret access key>
AWS_REGION=us-east-1
```
Initialize an EC2 instance:
Reference: [here](https://sumantmishra.medium.com/how-to-deploy-node-js-app-on-aws-with-github-db99758294f1)
Go to AWS dashboard -> EC2, then click Launch Instance.
Leave all on free tier defaults, but allow all connections. Create key-pair value.
Create.
Set security group rules (EDIT -> NEW -> ALL TRAFFIC -> ANYWHERE)
SSH in with downloaded key (Connect to Instance -> SSH Client).
`chmod 400 <KEY>.pem`
```
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
. ~/.nvm/nvm.sh
nvm install 16
```
```
sudo yum install git -y
git config --global user.name "Your Name"
git config --global user.email "Your Email"
```
```
ssh-keygen
cd .ssh
cat id_rsa.pub
```
ADD GENERATED SSH KEY TO GITLAB, (EXPIRY IN 1 DAY OR REMOVE AFTER REPO HAS BEEN CLONED IF YOU WANT TO BE EXTRA SECURE)
GIT CLONE
```
npm i
npm start
```
To do other things while your server is running:
* ctrl+z to stop,
* `bg` to continue in background
* `jobs` to list running tasks in bg
* `fg` to bring back to foreground (it's a stack, you can learn more online)
TO CREATE A SESSION THAT WILL STAY AFTER YOU LOGOUT:
```
screen -S <session-name>
npm start
```
To detach (go back to SSH):
CTRL + A + D
To re-attach (on new SSH session):
```
screen -ls
screen -r <screen name>
```
app.proto 0 → 100644
syntax = "proto3";
service App {
rpc GetProduct (ProductRequest) returns (Product) {}
rpc GetRandomProduct (EmptyRequest) returns (Product) {}
rpc GetAllProducts (EmptyRequest) returns (Products) {}
rpc GetAllCategories (EmptyRequest) returns (Categories) {}
rpc GetAllOrders (EmptyRequest) returns (Orders) {}
rpc GetAllUserOrders (UserRequest) returns (Orders) {}
rpc GetOrder (OrderRequest) returns (Order) {}
rpc GetUser (UserRequest) returns (User) {}
rpc GetAllUsers (EmptyRequest) returns (Users) {}
rpc PostOrder (Order) returns (Order) {}
rpc PatchAccountDetails (UserPatchRequest) returns (User) {}
}
message EmptyRequest {}
// Products
message ProductRequest {
string product_id = 1;
}
message Product {
string category_id = 1;
string images = 2;
int64 stock = 3;
int64 price = 4;
string description = 5;
string id = 6;
string name = 7;
}
message Products {
repeated Product products = 1;
}
// Orders
message OrderProduct {
string product_id = 1;
int64 quantity = 2;
}
message Order {
string user_id = 1;
string id = 2;
repeated OrderProduct products = 3;
int64 total_amount = 4;
}
message OrderRequest {
string id = 1;
}
message Orders {
repeated Order orders = 1;
}
// Categories
message Category {
string description = 1;
string id = 2;
int64 price = 3;
string name = 4;
}
message Categories {
repeated Category categories = 1;
}
// Users
message UserRequest {
string id = 1;
}
message UserPatchRequest {
string id = 1; // We assign user a unique ID, this shouldn't be changed. Following fields can be changed
string email = 2;
string password = 3;
}
message User {
string id = 1;
string email = 2;
}
message Users {
repeated User users = 1;
}
const db = process.argv[3];
const {
init,
queryRandomProduct,
queryUserById,
queryAllProducts,
queryProductById,
queryAllCategories,
queryAllOrders,
queryOrdersByUser,
queryOrderById,
queryAllUsers,
insertOrder,
updateUser,
} = require(db === "dynamo"
? "./dynamo_db.js"
: db === "sql"
? "./mysql_db.js"
: "");
const getRandomProduct = async (req, res) => {
const randProd = await queryRandomProduct();
res.send(randProd);
};
const getProduct = async (req, res) => {
const { productId } = req.params;
const product = await queryProductById(productId);
res.send(product);
};
const getProducts = async (req, res) => {
const { category } = req.query;
const products = await queryAllProducts(category);
res.send(products);
};
const getCategories = async (req, res) => {
const categories = await queryAllCategories();
res.send(categories);
};
const getAllOrders = async (req, res) => {
const orders = await queryAllOrders();
res.send(orders);
};
const getOrdersByUser = async (req, res) => {
const { userId } = req.query;
const orders = await queryOrdersByUser(userId);
res.send(orders);
};
const getOrder = async (req, res) => {
const { orderId } = req.params;
const order = await queryOrderById(orderId);
res.send(order);
};
const getUser = async (req, res) => {
const { userId } = req.params;
const user = await queryUserById(userId);
res.send(user);
};
const getUsers = async (req, res) => {
const users = await queryAllUsers();
res.send(users);
};
///TODO: Implement controller for POST /orders here
const patchUser = async (req, res) => {
const updates = req.body;
const { userId } = req.params;
const response = await updateUser(userId, updates);
res.send(response);
};
module.exports = {
init,
getProduct,
getRandomProduct,
getCategories,
getAllOrders,
getOrdersByUser,
getOrder,
getProducts,
getUser,
getUsers,
///TODO: Export controller for POST /orders,
patchUser,
};
require("dotenv").config();
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const {
GetCommand,
ScanCommand,
PutCommand,
UpdateCommand,
DynamoDBDocumentClient,
} = require("@aws-sdk/lib-dynamodb");
const uuid = require("uuid");
let client;
let docClient;
const init = () => {
client = new DynamoDBClient({ region: process.env.AWS_REGION });
docClient = DynamoDBDocumentClient.from(client);
console.log("DynamoDB connected!");
};
const queryRandomProduct = async () => {
///TODO: IMPLEMENT THIS
};
const queryProductById = async (productId) => {
const command = new GetCommand({
TableName: "Products",
Key: {
id: productId,
},
});
const response = await docClient.send(command);
return response.Item;
};
const queryAllProducts = async (category = "") => {
///TODO: Implement this
};
const queryAllCategories = async () => {
const command = new ScanCommand({
TableName: "Categories",
});
const response = await docClient.send(command);
return response.Items;
};
const queryAllOrders = async () => {
const command = new ScanCommand({
TableName: "Orders",
});
const response = await docClient.send(command);
return response.Items;
};
const queryOrdersByUser = async (userId) => {
const command = new ScanCommand({
TableName: "Orders",
FilterExpression: "user_id = :user_id",
ExpressionAttributeValues: {
":user_id": userId,
},
});
const response = await docClient.send(command);
return response.Items;
};
const queryOrderById = async (userId) => {
const command = new GetCommand({
TableName: "Orders",
Key: {
id: userId,
},
});
const response = await docClient.send(command);
return response.Item;
};
const queryUserById = async (userId) => {
const command = new GetCommand({
TableName: "Users",
Key: {
id: userId,
},
ProjectionExpression: "id, email",
});
const response = await docClient.send(command);
return response.Item;
};
const queryAllUsers = async () => {
const command = new ScanCommand({
TableName: "Users",
});
const response = await docClient.send(command);
return response.Items;
};
const insertOrder = async (order) => {
///TODO: Implement this
};
const updateUser = async (id, updates) => {
///TODO: Implement this
};
module.exports = {
init,
queryRandomProduct,
queryProductById,
queryAllProducts,
queryAllCategories,
queryAllOrders,
queryOrderById,
queryOrdersByUser,
queryUserById,
queryAllUsers,
insertOrder,
updateUser,
};
const db = process.argv[3];
const PROTO_PATH = "./app.proto";
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");
const {
init,
queryRandomProduct,
queryUserById,
queryAllProducts,
queryProductById,
queryAllCategories,
queryAllOrders,
queryOrdersByUser,
queryOrderById,
queryAllUsers,
insertOrder,
updateUser,
} = require(db === "dynamo"
? "./dynamo_db.js"
: db === "sql"
? "./mysql_db.js"
: "");
const { uuid } = require("uuidv4");
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
const app = grpc.loadPackageDefinition(packageDefinition).App;
init();
async function randomProduct(call, callback) {
const randProd = await queryRandomProduct();
callback(null, randProd);
}
async function allProducts(call, callback) {
const products = await queryAllProducts();
callback(null, { products });
}
async function product(call, callback) {
const { product_id } = call.request;
const product = await queryProductById(product_id);
callback(null, product);
}
async function categories(call, callback) {
const categories = await queryAllCategories();
callback(null, { categories });
}
async function allOrders(call, callback) {
const orders = await queryAllOrders();
callback(null, { orders });
}
async function ordersByUser(call, callback) {
const { id } = call.request;
const orders = await queryOrdersByUser(id);
callback(null, { orders });
}
async function order(call, callback) {
const { order_id } = call.request;
const order = await queryOrderById(order_id);
callback(null, order);
}
async function user(call, callback) {
const { id } = call.request;
const user = await queryUserById(id);
callback(null, user);
}
async function users(call, callback) {
const users = await queryAllUsers();
callback(null, { users });
}
/// TODO: Implement postOrder here
async function accountDetails(call, callback) {
const { id } = call.request;
delete call.request.id;
const user = await updateUser(id, call.request);
callback(null, user);
}
/**
* Starts an RPC server that receives requests for the Greeter service at the
* sample server port
*/
const server = new grpc.Server();
server.addService(app.service, {
getRandomProduct: randomProduct,
getAllProducts: allProducts,
getProduct: product,
getAllCategories: categories,
getAllOrders: allOrders,
getAllUserOrders: ordersByUser,
getOrder: order,
getUser: user,
getAllUsers: users,
///TODO: add postOrder:
patchAccountDetails: accountDetails,
});
server.bindAsync(
"0.0.0.0:3001",
grpc.ServerCredentials.createInsecure(),
() => {
console.log("App ready and listening on port 3001");
server.start();
},
);
if (process.argv.length < 4) {
console.error("Not enough command line arguments!");
return;
}
const mode = process.argv[2];
if (mode === "rest") require("./restServer.js");
else if (mode === "grpc") require("./grpcServer.js");
require("dotenv").config();
const util = require("util");
const uuid = require("uuid");
const mysql = require("mysql2-promise")();
const init = async () => {
mysql.configure({
host: process.env.RDS_HOSTNAME,
user: process.env.RDS_USERNAME,
password: process.env.RDS_PASSWORD,
port: process.env.RDS_PORT,
database: process.env.RDS_DATABASE,
});
// try {
// await connect();
// console.log("Database connected!");
// } catch (e) {
// console.error(e);
// }
};
const queryProductById = async (productId) => {
return await mysql.query(`SELECT *
FROM products
WHERE id = "${productId}";`);
};
const queryRandomProduct = async () => {
///TODO: Implement this
};
const queryAllProducts = async () => {
///TODO: Implement this
};
const queryAllCategories = async () => {
return (await mysql.query("SELECT * FROM categories;"))[0];
};
const queryAllOrders = async () => {
return (await mysql.query("SELECT * FROM orders;"))[0];
};
const queryOrdersByUser = async (userId) => {
return (
await mysql.query(`SELECT *
FROM orders
INNER JOIN order_items ON orders.id = order_items.order_id
WHERE user_id = "${userId}"`)
)[0]; // Not a perfect analog for NoSQL, since SQL cannot return a list.
};
const queryOrderById = async (id) => {
return (
await mysql.query(`SELECT *
FROM orders
WHERE id = "${id}"`)
)[0][0];
};
const queryUserById = async (id) => {
return (
await mysql.query(`SELECT *
FROM users
WHERE id = "${id}";`)
)[0][0];
};
const queryAllUsers = async () => {
return (await mysql.query("SELECT * FROM users"))[0];
};
const insertOrder = async (order) => {
///TODO: Implement this
};
const updateUser = async (id, updates) => {
///TODO: Implement this
};
module.exports = {
init,
queryRandomProduct,
queryProductById,
queryAllProducts,
queryAllCategories,
queryAllOrders,
queryOrderById,
queryOrdersByUser,
queryUserById,
queryAllUsers,
insertOrder,
updateUser,
};
This diff is collapsed.
{
"name": "lab-1-skeleton",
"version": "1.0.0",
"description": "Skeleton code for SE464 lab 1",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node main.js"
},
"author": "based-jaml",
"license": "ISC",
"dependencies": {
"@aws-sdk/client-dynamodb": "^3.352.0",
"@aws-sdk/client-s3": "^3.359.0",
"@aws-sdk/lib-dynamodb": "^3.352.0",
"@grpc/grpc-js": "^1.9.0",
"@grpc/proto-loader": "^0.7.8",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"dotenv": "^16.1.4",
"express": "^4.18.2",
"google-protobuf": "^3.21.2",
"morgan": "^1.10.0",
"mysql2": "^3.3.5",
"mysql2-promise": "^0.1.4",
"uuidv4": "^6.2.13"
}
}
const express = require("express");
const cors = require("cors");
const morgan = require("morgan");
const bodyParser = require("body-parser");
const app = express();
const port = 3000;
app.use(cors());
app.use(morgan("tiny"));
app.use(bodyParser.json());
const {
init,
getProduct,
getRandomProduct,
getProducts,
getCategories,
getAllOrders,
getOrdersByUser,
getOrder,
getUser,
getUsers,
///TODO: Write controller function for POST /orders,
patchUser,
} = require("./controller.js");
init();
app.get("/", (req, res) => res.send("Hello, World!"));
app.get("/product/:productId", getProduct); // Gets a product by product id
app.get("/randomproduct", getRandomProduct); // I'm feeling lucky type
app.get("/products", getProducts); // Gets all products, or by category
app.get("/categories", getCategories); // Gets all categories
app.get("/allorders", getAllOrders);
app.get("/orders", getOrdersByUser); // Gets all of a single user's orders
app.get("/order/:orderId", getOrder); // Gets more details on a specific order by id
app.get("/user/:userId", getUser); // Gets details on a specific user by username
app.get("/users", getUsers);
///TODO: Implement POST /orders for order creation
app.patch("/user/:userId", patchUser);
app.listen(port, () => {
console.log(`App ready and listening on port ${port}`);
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment