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

Add a planet microservice #2396

Merged
merged 1 commit into from
Oct 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions config/env.development
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ PARSER_PORT=10000
PARSER_URL=http://localhost/v1/parser


################################################################################
# Planet Service
################################################################################

# Planet Service Port (default is 9876)
PLANET_PORT=9876


################################################################################
# Telescope 1.0 Legacy Environment
################################################################################
Expand Down
8 changes: 8 additions & 0 deletions config/env.production
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ PARSER_PORT=10000
PARSER_URL=https://api.telescope.cdot.systems/v1/parser


################################################################################
# Planet Service
################################################################################

# Planet Service Port (default is 9876)
PLANET_PORT=9876


################################################################################
# Telescope 1.0 Legacy Environment
################################################################################
Expand Down
8 changes: 8 additions & 0 deletions config/env.staging
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,14 @@ PARSER_PORT=10000
PARSER_URL=https://dev.api.telescope.cdot.systems/v1/parser


################################################################################
# Planet Service
################################################################################

# Planet Service Port (default is 9876)
PLANET_PORT=9876


################################################################################
# Telescope 1.0 Legacy Environment
################################################################################
Expand Down
18 changes: 16 additions & 2 deletions config/nginx.conf.development.template
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,22 @@ http {

# Front-end and Legacy Back-end node.js app are served here
server {
listen 80 default_server;
server_name localhost:8000;
listen 8000 default_server;
server_name localhost;

# Cache content served by /legacy forever
location /legacy {
proxy_cache_bypass 1;
proxy_set_header Connection "";
proxy_pass http://planet:9876;
}

# Cache content served by /planet forever
location /planet {
proxy_cache_bypass 1;
proxy_set_header Connection "";
proxy_pass http://planet:9876;
}

# Static next.js front-end
location / {
Expand Down
21 changes: 20 additions & 1 deletion config/nginx.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,26 @@ http {
location /legacy {
expires max;
add_header Cache-Control "public, max-age=31536000, immutable";
proxy_pass http://telescope:3000;
proxy_pass http://planet:9876;
}

# Cache content served by /planet forever
location /planet {
# Defines conditions under which the response will not be taken from a cache
# In this case, cache will be ignored when requested from client
proxy_cache_bypass $http_cache_control;

# Sets caching time for different response codes
proxy_cache_valid 200 307 10m;
proxy_cache_valid 404 1m;

# Disables processing of certain response header fields from the proxied server
proxy_ignore_headers "Cache-Control" "Expires";

# Added 'X-Proxy-Cache' header to be able to monitor caching
add_header X-Proxy-Cache $upstream_cache_status;

proxy_pass http://planet:9876;
}

# Non-cached /portainer route
Expand Down
8 changes: 7 additions & 1 deletion docker/development.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ services:
volumes:
- ../config/nginx.conf.development.template:/etc/nginx/nginx.conf
ports:
- '8000:80'
- '8000:8000'

traefik:
command:
Expand Down Expand Up @@ -94,3 +94,9 @@ services:
# For development and testing, the Parser service needs to contact the users
# service directly via Docker vs through the http://localhost domain.
- USERS_URL=http://users:7000

planet:
ports:
- '9876:9876'
environment:
- POSTS_URL=http://posts:5555
11 changes: 11 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,17 @@ services:
- 'traefik.http.middlewares.strip_parser_prefix.stripprefix.forceSlash=true'
- 'traefik.http.routers.parser.middlewares=strip_parser_prefix'

# planet service
planet:
container_name: 'planet'
build:
context: ../src/api/planet
dockerfile: Dockerfile
environment:
- NODE_ENV
- PLANET_PORT
- POSTS_URL

##############################################################################
# Third-Party Dependencies and Support Services
##############################################################################
Expand Down
4 changes: 4 additions & 0 deletions docker/production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ services:
parser:
restart: unless-stopped

# planet service
planet:
restart: unless-stopped

# search service
search:
restart: unless-stopped
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@
"dotenv": "8.2.0",
"entities": "2.2.0",
"express": "4.17.1",
"express-handlebars": "5.3.0",
"express-healthcheck": "0.1.0",
"express-pino-logger": "6.0.0",
"express-session": "1.17.1",
Expand Down
6 changes: 6 additions & 0 deletions src/api/planet/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.dockerignore
node_modules
npm-debug.log
Dockerfile
.git
.gitignore
14 changes: 14 additions & 0 deletions src/api/planet/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM node:lts-alpine as base

# https://snyk.io/blog/10-best-practices-to-containerize-nodejs-web-applications-with-docker/
RUN apk add dumb-init

WORKDIR /app

COPY --chown=node:node . .

RUN npm install --only=production --no-package-lock

USER node

CMD ["dumb-init", "npm", "start"]
File renamed without changes.
2 changes: 2 additions & 0 deletions src/api/planet/env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PLANET_PORT=9876
POSTS_URL=http://localhost/v1/posts
28 changes: 28 additions & 0 deletions src/api/planet/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@senecacdot/planet-service",
"private": true,
"version": "1.0.0",
"description": "A service the planet version of Telescope",
"scripts": {
"dev": "env-cmd -f env.local nodemon src/server.js",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

"start": "node src/server.js"
},
"repository": "Seneca-CDOT/telescope",
"license": "BSD-2-Clause",
"bugs": {
"url": "https://github.com/Seneca-CDOT/telescope/issues"
},
"homepage": "https://github.com/Seneca-CDOT/telescope#readme",
"dependencies": {
"@senecacdot/satellite": "^1.x",
"express": "^4.17.1",
"express-handlebars": "^5.3.4"
},
"engines": {
"node": ">=12.0.0"
},
"devDependencies": {
"nodemon": "^2.0.7",
"env-cmd": "^10.1.0"
}
}
34 changes: 34 additions & 0 deletions src/api/planet/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const { static } = require('express');
const expressHandlebars = require('express-handlebars');
const { Satellite } = require('@senecacdot/satellite');
const path = require('path');
const planet = require('./planet');

const service = new Satellite({
beforeRouter(app) {
app.engine('handlebars', expressHandlebars());
app.set('views', path.join(__dirname, '../views'));
app.set('view engine', 'handlebars');
},
helmet: {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
fontSrc: ["'self'", 'https:', 'data:'],
frameSrc: ["'self'", '*.youtube.com', '*.vimeo.com'],
frameAncestors: ["'self'"],
imgSrc: ["'self'", 'data:', 'https:'],
scriptSrc: ["'self'"],
styleSrc: ["'self'", 'https:', "'unsafe-inline'"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
},
},
},
});

// Legacy CDOT Planet static assets
service.router.use('/legacy', static(path.join(__dirname, '../static')));
service.router.use('/planet', planet);

module.exports = service;
52 changes: 29 additions & 23 deletions src/backend/web/routes/planet.js → src/api/planet/src/planet.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
const express = require('express');
const { Router, logger, fetch } = require('@senecacdot/satellite');
const router = Router();

const { getPosts, getFeeds } = require('../../utils/storage');
const Post = require('../../data/post');
const Feed = require('../../data/feed');
const { logger } = require('../../utils/logger');

const router = express.Router();
const { POSTS_URL } = process.env;
const FEEDS_URL = `${POSTS_URL}/feeds`;

// Format a Date into a String like `Saturday, September 17, 2016`
function formatDate(date) {
const formatDate = (date) => {
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
return date.toLocaleDateString('en-US', options);
}
};

/**
* Get most recent 50 posts, and group them according to
* day, channel, date.
*/
async function getPostDataGrouped() {
const ids = await getPosts(0, 50);
const posts = await Promise.all(ids.map(Post.byId));

const getPostDataGrouped = (posts) => {
// We group the posts into nested objects: days > authors > posts
const grouped = { days: {} };
posts.forEach((post) => {
posts?.forEach((post) => {
if (!post) {
return;
}

// Top level is formated Day strings
// Top level is formatted Day strings
post.updated = new Date(post.updated);
const formatted = formatDate(post.updated);
if (!grouped.days[formatted]) {
grouped.days[formatted] = {};
Expand All @@ -48,22 +43,33 @@ async function getPostDataGrouped() {
});

return grouped;
}
};

async function getFeedData() {
const feedIds = await getFeeds();
const feeds = await Promise.all(feedIds.map(Feed.byId));
return feeds.sort((a, b) => {
const sort = (feeds) => {
return feeds?.sort((a, b) => {
if (a.author < b.author) return -1;
if (a.author > b.author) return 1;
return 0;
});
}
};

const fetchData = async (dataUrl) => {
try {
const response = await fetch(dataUrl);
const data = await response.json();
return Promise.all(data.map((item) => fetch(`${dataUrl}/${item.id}`).then((r) => r.json())));
} catch (e) {
logger.error(e);
}
return;
};

router.get('/', async (req, res, next) => {
try {
const [grouped, feeds] = await Promise.all([getPostDataGrouped(), getFeedData()]);
res.render('planet', { feeds, ...grouped });
const [feeds, posts] = await Promise.all([fetchData(FEEDS_URL), fetchData(POSTS_URL)]);

const grouped = getPostDataGrouped(posts);
res.render('planet', { feeds: sort(feeds), ...grouped });
} catch (error) {
logger.error({ error }, 'Error processing posts from Redis');
next(error);
Expand Down
5 changes: 5 additions & 0 deletions src/api/planet/src/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const service = require('.');

const port = parseInt(process.env.PLANET_PORT || 9876, 10);

service.start(port);
2 changes: 2 additions & 0 deletions src/api/posts/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ const { Satellite } = require('@senecacdot/satellite');
const redis = require('./redis');

const posts = require('./routes/posts');
const feeds = require('./routes/feeds');
humphd marked this conversation as resolved.
Show resolved Hide resolved

const service = new Satellite({
healthCheck: () => redis.ping(),
});

service.router.use('/feeds', feeds);
service.router.use('/', posts);

module.exports = service;
Loading