Rewriting original page server to use async.

This commit is contained in:
Samuel Clay 2024-02-25 17:13:38 -05:00
parent 9c15c1ac60
commit d6643bb8ab
6 changed files with 91 additions and 74 deletions

1
.gitignore vendored
View file

@ -58,6 +58,7 @@ docker/postgres/postgres.conf
# Local configuration file (sdk path, etc) # Local configuration file (sdk path, etc)
/originals /originals
/node/originals
media/safari/NewsBlur.safariextz media/safari/NewsBlur.safariextz
# IDE files # IDE files

View file

@ -18,7 +18,7 @@
redis_target: "redis-user" redis_target: "redis-user"
redis_port: 6381 redis_port: 6381
- port: 9122 - port: 9122
redis_target: "redis-sessions" redis_target: "redis-session"
redis_port: 6382 redis_port: 6382
- port: 9123 - port: 9123
redis_target: "redis-story" redis_target: "redis-story"
@ -39,7 +39,7 @@
- port: 9121 - port: 9121
redis_target: "redis-user" redis_target: "redis-user"
- port: 9122 - port: 9122
redis_target: "redis-sessions" redis_target: "redis-session"
- port: 9123 - port: 9123
redis_target: "redis-story" redis_target: "redis-story"
- port: 9124 - port: 9124

View file

@ -880,7 +880,6 @@ def load_feed_page(request, feed_id):
raise Http404 raise Http404
feed = Feed.get_by_id(feed_id) feed = Feed.get_by_id(feed_id)
if feed and feed.has_page and not feed.has_page_exception: if feed and feed.has_page and not feed.has_page_exception:
if settings.BACKED_BY_AWS.get('pages_on_node'): if settings.BACKED_BY_AWS.get('pages_on_node'):
domain = Site.objects.get_current().domain domain = Site.objects.get_current().domain
@ -889,8 +888,9 @@ def load_feed_page(request, feed_id):
feed.pk, feed.pk,
) )
try: try:
page_response = requests.get(url) page_response = requests.get(url, verify=not settings.DEBUG)
except requests.ConnectionError: except requests.ConnectionError as e:
logging.user(request, f"~FR~SBError loading original page: {url} {e}")
page_response = None page_response = None
if page_response and page_response.status_code == 200: if page_response and page_response.status_code == 200:
response = HttpResponse(page_response.content, content_type="text/html; charset=utf-8") response = HttpResponse(page_response.content, content_type="text/html; charset=utf-8")

View file

@ -50,6 +50,7 @@ services:
- 8008:8008 - 8008:8008
volumes: volumes:
- ${PWD}/node:/srv - ${PWD}/node:/srv
- ${PWD}/node/originals:/srv/originals
imageproxy: imageproxy:
container_name: imageproxy container_name: imageproxy

View file

@ -4,56 +4,66 @@ fs = require 'fs'
mkdirp = require 'mkdirp' mkdirp = require 'mkdirp'
log = require './log.js' log = require './log.js'
fsPromises = fs.promises
mkdirpPromise = require('util').promisify(mkdirp)
original_page = (app) => original_page = (app) =>
DEV = process.env.NODE_ENV == 'development' || process.env.NODE_ENV == 'docker' || process.env.NODE_ENV == 'debug' DEV = process.env.NODE_ENV == 'development' || process.env.NODE_ENV == 'docker' || process.env.NODE_ENV == 'debug'
DB_PATH = if DEV then 'originals' else '/srv/originals' DB_PATH = '/srv/originals'
app.use busboy() app.use busboy()
app.get /^\/original_page\/(\d+)\/?/, (req, res) => app.get /^\/original_page\/(\d+)\/?/, (req, res) ->
if req.query.test return res.end "OK" if req.query.test
return res.end "OK"
feedId = parseInt(req.params[0], 10) feedId = parseInt req.params[0], 10
etag = req.header('If-None-Match') etag = req.header 'If-None-Match'
lastModified = req.header('If-Modified-Since') lastModified = req.header 'If-Modified-Since'
feedIdDir = splitFeedId feedId feedIdDir = splitFeedId feedId
filePath = "#{DB_PATH}/#{feedIdDir}.zhtml" filePath = "#{DB_PATH}/#{feedIdDir}.zhtml"
fs.exists filePath, (exists, err) -> # Convert to async flow with try/catch using CoffeeScript's then/catch for Promises
log.debug "Loading: #{feedId} (#{filePath}). " + fsPromises.stat(filePath).then (stats) ->
"#{if exists then "" else "NOT FOUND"}" fileEtag = Date.parse(stats.mtime).toString()
if not exists if etag is fileEtag or lastModified is stats.mtime.toISOString()
return res.sendStatus 404 log.debug "Not modified: #{feedId} (#{filePath})"
fs.stat filePath, (err, stats) -> res.sendStatus 304
if not err and etag and stats.mtime == etag else
return res.sendStatus 304 fsPromises.readFile(filePath).then (content) ->
if not err and lastModified and stats.mtime == lastModified log.debug "Sending: #{feedId} (#{filePath}) #{stats.size} bytes"
return res.sendStatus 304 res.header 'Etag', fileEtag
fs.readFile filePath, (err, content) ->
res.header 'Etag', Date.parse(stats.mtime)
res.send content res.send content
.catch (err) ->
if err.code is 'ENOENT'
log.debug "Original page not found: #{feedId} (#{filePath})"
res.sendStatus 404
else
log.debug "Error reading original page: #{feedId} (#{filePath}) #{err}"
res.sendStatus 500
app.post /^\/original_page\/(\d+)\/?/, (req, res) => app.post /^\/original_page\/(\d+)\/?/, (req, res) ->
feedId = parseInt(req.params[0], 10) feedId = parseInt req.params[0], 10
feedIdDir = splitFeedId feedId feedIdDir = splitFeedId feedId
req.pipe req.busboy
req.busboy.on 'file', (fieldname, file, filename) ->
# log.debug "Uploading #{fieldname} / #{file} / #{filename}"
filePath = "#{DB_PATH}/#{feedIdDir}.zhtml" filePath = "#{DB_PATH}/#{feedIdDir}.zhtml"
filePathDir = path.dirname filePath filePathDir = path.dirname filePath
mkdirp filePathDir, (err) ->
log.debug err if err # Ensure directory exists before proceeding
mkdirpPromise(filePathDir).then ->
fstream = fs.createWriteStream filePath fstream = fs.createWriteStream filePath
req.pipe req.busboy
req.busboy.on 'file', (fieldname, file, filename) ->
file.pipe fstream file.pipe fstream
fstream.on 'close', -> fstream.on 'close', ->
fs.stat filePath, (err, stats) -> fsPromises.stat(filePath).then (stats) ->
log.debug err if err
log.debug "Saving: #{feedId} (#{filePath}) #{stats.size} bytes" log.debug "Saving: #{feedId} (#{filePath}) #{stats.size} bytes"
res.send "OK" res.send "OK"
.catch (err) ->
log.debug err
res.sendStatus 500
splitFeedId = (feedId) -> splitFeedId = (feedId) ->

View file

@ -1,6 +1,6 @@
// Generated by CoffeeScript 2.6.1 // Generated by CoffeeScript 2.6.1
(function() { (function() {
var busboy, fs, log, mkdirp, original_page, path; var busboy, fs, fsPromises, log, mkdirp, mkdirpPromise, original_page, path;
path = require('path'); path = require('path');
@ -12,12 +12,16 @@
log = require('./log.js'); log = require('./log.js');
fsPromises = fs.promises;
mkdirpPromise = require('util').promisify(mkdirp);
original_page = (app) => { original_page = (app) => {
var DB_PATH, DEV, splitFeedId; var DB_PATH, DEV, splitFeedId;
DEV = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'docker' || process.env.NODE_ENV === 'debug'; DEV = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'docker' || process.env.NODE_ENV === 'debug';
DB_PATH = DEV ? 'originals' : '/srv/originals'; DB_PATH = '/srv/originals';
app.use(busboy()); app.use(busboy());
app.get(/^\/original_page\/(\d+)\/?/, (req, res) => { app.get(/^\/original_page\/(\d+)\/?/, function(req, res) {
var etag, feedId, feedIdDir, filePath, lastModified; var etag, feedId, feedIdDir, filePath, lastModified;
if (req.query.test) { if (req.query.test) {
return res.end("OK"); return res.end("OK");
@ -27,52 +31,53 @@
lastModified = req.header('If-Modified-Since'); lastModified = req.header('If-Modified-Since');
feedIdDir = splitFeedId(feedId); feedIdDir = splitFeedId(feedId);
filePath = `${DB_PATH}/${feedIdDir}.zhtml`; filePath = `${DB_PATH}/${feedIdDir}.zhtml`;
return fs.exists(filePath, function(exists, err) { // Convert to async flow with try/catch using CoffeeScript's then/catch for Promises
log.debug(`Loading: ${feedId} (${filePath}). ` + `${exists ? "" : "NOT FOUND"}`); return fsPromises.stat(filePath).then(function(stats) {
if (!exists) { var fileEtag;
return res.sendStatus(404); fileEtag = Date.parse(stats.mtime).toString();
} if (etag === fileEtag || lastModified === stats.mtime.toISOString()) {
return fs.stat(filePath, function(err, stats) { log.debug(`Not modified: ${feedId} (${filePath})`);
if (!err && etag && stats.mtime === etag) {
return res.sendStatus(304); return res.sendStatus(304);
} } else {
if (!err && lastModified && stats.mtime === lastModified) { return fsPromises.readFile(filePath).then(function(content) {
return res.sendStatus(304); log.debug(`Sending: ${feedId} (${filePath}) ${stats.size} bytes`);
} res.header('Etag', fileEtag);
return fs.readFile(filePath, function(err, content) {
res.header('Etag', Date.parse(stats.mtime));
return res.send(content); return res.send(content);
}); });
}
}).catch(function(err) {
if (err.code === 'ENOENT') {
log.debug(`Original page not found: ${feedId} (${filePath})`);
return res.sendStatus(404);
} else {
log.debug(`Error reading original page: ${feedId} (${filePath}) ${err}`);
return res.sendStatus(500);
}
}); });
}); });
}); app.post(/^\/original_page\/(\d+)\/?/, function(req, res) {
app.post(/^\/original_page\/(\d+)\/?/, (req, res) => { var feedId, feedIdDir, filePath, filePathDir;
var feedId, feedIdDir;
feedId = parseInt(req.params[0], 10); feedId = parseInt(req.params[0], 10);
feedIdDir = splitFeedId(feedId); feedIdDir = splitFeedId(feedId);
req.pipe(req.busboy);
return req.busboy.on('file', function(fieldname, file, filename) {
var filePath, filePathDir;
// log.debug "Uploading #{fieldname} / #{file} / #{filename}"
filePath = `${DB_PATH}/${feedIdDir}.zhtml`; filePath = `${DB_PATH}/${feedIdDir}.zhtml`;
filePathDir = path.dirname(filePath); filePathDir = path.dirname(filePath);
return mkdirp(filePathDir, function(err) { // Ensure directory exists before proceeding
return mkdirpPromise(filePathDir).then(function() {
var fstream; var fstream;
if (err) {
log.debug(err);
}
fstream = fs.createWriteStream(filePath); fstream = fs.createWriteStream(filePath);
req.pipe(req.busboy);
return req.busboy.on('file', function(fieldname, file, filename) {
file.pipe(fstream); file.pipe(fstream);
return fstream.on('close', function() { return fstream.on('close', function() {
return fs.stat(filePath, function(err, stats) { return fsPromises.stat(filePath).then(function(stats) {
if (err) {
log.debug(err);
}
log.debug(`Saving: ${feedId} (${filePath}) ${stats.size} bytes`); log.debug(`Saving: ${feedId} (${filePath}) ${stats.size} bytes`);
return res.send("OK"); return res.send("OK");
}); });
}); });
}); });
}).catch(function(err) {
log.debug(err);
return res.sendStatus(500);
}); });
}); });
splitFeedId = function(feedId) { splitFeedId = function(feedId) {