Skip to content

Commit 0aab2ea

Browse files
andrewshellclaude
andcommitted
Replace moment.js with Day.js for date/time operations
- Replace deprecated moment.js with modern Day.js library - Create dayjs-wrapper.js for dynamic ESM imports in CommonJS - Update all services and controllers to use async dayjs pattern - Maintain API compatibility while improving performance - All tests passing with new date library 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent b5633bf commit 0aab2ea

15 files changed

+152
-96
lines changed

app.js

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ const config = require('./config'),
44
cors = require('cors'),
55
express = require('express'),
66
exphbs = require('express-handlebars'),
7-
moment = require('moment'),
7+
getDayjs = require('./services/dayjs-wrapper'),
88
mongodb = require('./services/mongodb'),
99
morgan = require('morgan');
1010
// removeExpiredSubscriptions = require('./services/remove-expired-subscriptions');
1111

12-
let app, hbs, server;
12+
let app, hbs, server, dayjs;
1313

1414
require('console-stamp')(console, 'HH:MM:ss.l');
1515

@@ -22,18 +22,23 @@ morgan.format('mydate', () => {
2222
return df(new Date(), 'HH:MM:ss.l');
2323
});
2424

25+
// Initialize dayjs at startup
26+
async function initializeDayjs() {
27+
dayjs = await getDayjs();
28+
}
29+
2530
app = express();
2631
require('express-ws')(app);
2732

2833
app.use(morgan('[:mydate] :method :url :status :res[content-length] - :remote-addr - :response-time ms'));
2934

3035
app.use(cors());
3136

32-
// Configure handlebars template engine to work with moment
37+
// Configure handlebars template engine to work with dayjs
3338
hbs = exphbs.create({
3439
helpers: {
3540
formatDate: (datetime, format) => {
36-
return moment(datetime).format(format);
41+
return dayjs(datetime).format(format);
3742
}
3843
}
3944
});
@@ -52,25 +57,29 @@ app.use(express.static('public', {
5257
app.use(require('./controllers'));
5358

5459
// Start server
55-
mongodb.connect('rsscloud', config.mongodbUri)
56-
.then(() => {
57-
server = app.listen(config.port, () => {
58-
app.locals.host = config.domain;
59-
app.locals.port = server.address().port;
60-
61-
if (app.locals.host.indexOf(':') > -1) {
62-
app.locals.host = '[' + app.locals.host + ']';
60+
async function startServer() {
61+
await initializeDayjs();
62+
await mongodb.connect('rsscloud', config.mongodbUri);
63+
64+
server = app.listen(config.port, () => {
65+
app.locals.host = config.domain;
66+
app.locals.port = server.address().port;
67+
68+
if (app.locals.host.indexOf(':') > -1) {
69+
app.locals.host = '[' + app.locals.host + ']';
70+
}
71+
72+
console.log(`Listening at http://${app.locals.host}:${app.locals.port}`);
73+
})
74+
.on('error', (error) => {
75+
switch (error.code) {
76+
case 'EADDRINUSE':
77+
console.log(`Error: Port ${config.port} is already in use.`);
78+
break;
79+
default:
80+
console.log(error.code);
6381
}
82+
});
83+
}
6484

65-
console.log(`Listening at http://${app.locals.host}:${app.locals.port}`);
66-
})
67-
.on('error', (error) => {
68-
switch (error.code) {
69-
case 'EADDRINUSE':
70-
console.log(`Error: Port ${config.port} is already in use.`);
71-
break;
72-
default:
73-
console.log(error.code);
74-
}
75-
});
76-
});
85+
startServer().catch(console.error);

controllers/rpc2.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
const bodyParser = require('body-parser'),
33
ErrorResponse = require('../services/error-response'),
44
express = require('express'),
5+
getDayjs = require('../services/dayjs-wrapper'),
56
logEvent = require('../services/log-event'),
6-
moment = require('moment'),
77
parseRpcRequest = require('../services/parse-rpc-request'),
88
parseNotifyParams = require('../services/parse-notify-params'),
99
parsePingParams = require('../services/parse-ping-params'),
@@ -33,14 +33,15 @@ function handleError(req, res, err) {
3333
processResponse(req, res, rpcReturnFault(4, err.message));
3434
}
3535

36-
router.post('/', textParser, function(req, res) {
36+
router.post('/', textParser, async function(req, res) {
3737
let params;
38+
const dayjs = await getDayjs();
3839
parseRpcRequest(req)
3940
.then(request => {
4041
logEvent(
4142
'XmlRpc',
4243
request.methodName,
43-
moment().format('x')
44+
dayjs().format('x')
4445
);
4546

4647
switch (request.methodName) {

package-lock.json

Lines changed: 12 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"express-handlebars": "^5.3.3",
2828
"express-ws": "^5.0.2",
2929
"markdown-it": "^14.1.0",
30-
"moment": "^2.30.1",
30+
"dayjs": "^1.11.13",
3131
"mongodb": "6.17.0",
3232
"morgan": "^1.10.0",
3333
"nconf": "^0.13.0",

services/dayjs-wrapper.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
let dayjs;
2+
3+
async function getDayjs() {
4+
if (!dayjs) {
5+
const dayjsModule = await import('dayjs');
6+
const utc = await import('dayjs/plugin/utc.js');
7+
const advancedFormat = await import('dayjs/plugin/advancedFormat.js');
8+
const duration = await import('dayjs/plugin/duration.js');
9+
const customParseFormat = await import('dayjs/plugin/customParseFormat.js');
10+
11+
dayjs = dayjsModule.default;
12+
dayjs.extend(utc.default);
13+
dayjs.extend(advancedFormat.default);
14+
dayjs.extend(duration.default);
15+
dayjs.extend(customParseFormat.default);
16+
}
17+
return dayjs;
18+
}
19+
20+
module.exports = getDayjs;

services/init-resource.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
const moment = require('moment');
1+
const getDayjs = require('./dayjs-wrapper');
22

3-
function initResource(resource) {
3+
async function initResource(resource) {
4+
const dayjs = await getDayjs();
45
const defaultResource = {
56
flDirty: true,
67
lastSize: 0,
78
lastHash: '',
89
ctChecks: 0,
9-
whenLastCheck: new Date(moment.utc('0', 'x').format()),
10+
whenLastCheck: new Date(dayjs.utc('0', 'x').format()),
1011
ctUpdates: 0,
11-
whenLastUpdate: new Date(moment.utc('0', 'x').format())
12+
whenLastUpdate: new Date(dayjs.utc('0', 'x').format())
1213
};
1314

1415
return Object.assign({}, defaultResource, resource);

services/init-subscription.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
const config = require('../config'),
2-
moment = require('moment');
2+
getDayjs = require('./dayjs-wrapper');
33

4-
function initSubscription(subscriptions, notifyProcedure, apiurl, protocol) {
4+
async function initSubscription(subscriptions, notifyProcedure, apiurl, protocol) {
5+
const dayjs = await getDayjs();
56
const defaultSubscription = {
67
ctUpdates: 0,
7-
whenLastUpdate: new Date(moment.utc('0', 'x').format()),
8+
whenLastUpdate: new Date(dayjs.utc('0', 'x').format()),
89
ctErrors: 0,
910
ctConsecutiveErrors: 0,
10-
whenLastError: new Date(moment.utc('0', 'x').format()),
11-
whenExpires: new Date(moment().utc().add(config.ctSecsResourceExpire, 'seconds').format()),
11+
whenLastError: new Date(dayjs.utc('0', 'x').format()),
12+
whenExpires: new Date(dayjs().utc().add(config.ctSecsResourceExpire, 'seconds').format()),
1213
url: apiurl,
1314
notifyProcedure,
1415
protocol

services/log-event.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
const logEmitter = require('./log-emitter'),
2-
moment = require('moment'),
1+
const getDayjs = require('./dayjs-wrapper'),
2+
logEmitter = require('./log-emitter'),
33
mongodb = require('./mongodb');
44

55
async function logEvent(eventtype, htmltext, startticks, req) {
6+
const dayjs = await getDayjs();
67
let secs, time;
78

8-
time = moment();
9+
time = dayjs();
910
secs = (parseInt(time.format('x'), 10) - parseInt(startticks, 10)) / 1000;
1011

1112
if (undefined === req) {

services/notify-subscribers.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const appMessages = require('./app-messages'),
22
config = require('../config'),
3+
getDayjs = require('./dayjs-wrapper'),
34
logEvent = require('./log-event'),
4-
moment = require('moment'),
55
mongodb = require('./mongodb'),
66
notifyOne = require('./notify-one'),
77
sprintf = require('sprintf-js').sprintf,
@@ -28,8 +28,9 @@ async function upsertSubscriptions(subscriptions) {
2828
}
2929

3030
async function notifyOneSubscriber(resourceUrl, subscription) {
31+
const dayjs = await getDayjs();
3132
const apiurl = subscription.url,
32-
startticks = moment().format('x'),
33+
startticks = dayjs().format('x'),
3334
parts = url.parse(apiurl),
3435
notifyProcedure = subscription.notifyProcedure,
3536
protocol = subscription.protocol;
@@ -39,7 +40,7 @@ async function notifyOneSubscriber(resourceUrl, subscription) {
3940

4041
subscription.ctUpdates += 1;
4142
subscription.ctConsecutiveErrors = 0;
42-
subscription.whenLastUpdate = new Date(moment().utc().format());
43+
subscription.whenLastUpdate = new Date(dayjs().utc().format());
4344

4445
await logEvent(
4546
'Notify',
@@ -51,7 +52,7 @@ async function notifyOneSubscriber(resourceUrl, subscription) {
5152

5253
subscription.ctErrors += 1;
5354
subscription.ctConsecutiveErrors += 1;
54-
subscription.whenLastError = new Date(moment().utc().format());
55+
subscription.whenLastError = new Date(dayjs().utc().format());
5556

5657
await logEvent(
5758
'NotifyFailed',
@@ -61,8 +62,9 @@ async function notifyOneSubscriber(resourceUrl, subscription) {
6162
}
6263
}
6364

64-
function filterSubscribers(subscription) {
65-
if (moment().isAfter(subscription.whenExpires)) {
65+
async function filterSubscribers(subscription) {
66+
const dayjs = await getDayjs();
67+
if (dayjs().isAfter(subscription.whenExpires)) {
6668
return false;
6769
}
6870

@@ -76,7 +78,14 @@ function filterSubscribers(subscription) {
7678
async function notifySubscribers(resourceUrl) {
7779
const subscriptions = await fetchSubscriptions(resourceUrl);
7880

79-
await Promise.all(subscriptions.pleaseNotify.filter(filterSubscribers).map(notifyOneSubscriber.bind(null, resourceUrl)));
81+
const validSubscriptions = [];
82+
for (const subscription of subscriptions.pleaseNotify) {
83+
if (await filterSubscribers(subscription)) {
84+
validSubscriptions.push(subscription);
85+
}
86+
}
87+
88+
await Promise.all(validSubscriptions.map(notifyOneSubscriber.bind(null, resourceUrl)));
8089

8190
console.log('upserting subscriptions');
8291

0 commit comments

Comments
 (0)