diff --git a/lib/session.js b/lib/session.js index dd196aaa..d635f75a 100644 --- a/lib/session.js +++ b/lib/session.js @@ -1,12 +1,14 @@ +import { parseToken } from 'next-basics'; +import { validate } from 'uuid'; import { uuid } from 'lib/crypto'; import redis, { DELETED } from 'lib/redis'; import { getClientInfo, getJsonBody } from 'lib/request'; -import { parseToken } from 'next-basics'; -import { validate } from 'uuid'; +import { createSession, getSessionByUuid, getWebsiteByUuid } from 'queries'; export async function getSession(req) { const { payload } = getJsonBody(req); const hasRedis = process.env.REDIS_URL; + const hasClickhouse = process.env.CLICKHOUSE_URL; if (!payload) { throw new Error('Invalid request'); @@ -35,16 +37,14 @@ export async function getSession(req) { websiteId = Number(await redis.client.get(`website:${website_uuid}`)); } - // // Check database if does not exists in Redis - // if (!websiteId) { - // const website = await getWebsiteByUuid(website_uuid); - // websiteId = website ? website.website_id : null; - // } + // Check database if does not exists in Redis + if (!websiteId) { + const website = await getWebsiteByUuid(website_uuid); + websiteId = website ? website.website_id : null; + } if (!websiteId || websiteId === DELETED) { - throw new Error( - `Website not found: ${website_uuid} : ${process.env.REDIS_URL} : ${process.env.CLICKHOUSE_URL}`, - ); + throw new Error(`Website not found: ${website_uuid}`); } const { userAgent, browser, os, ip, country, device } = await getClientInfo(req, payload); @@ -53,17 +53,49 @@ export async function getSession(req) { let sessionId = null; let session = null; - session = { - session_id: sessionId, - session_uuid, - hostname, - browser, - os, - screen, - language, - country, - device, - }; + if (!hasClickhouse) { + // Check if session exists + if (hasRedis) { + sessionId = Number(await redis.client.get(`session:${session_uuid}`)); + } + + // Check database if does not exists in Redis + if (!sessionId) { + session = await getSessionByUuid(session_uuid); + sessionId = session ? session.session_id : null; + } + + if (!sessionId) { + try { + session = await createSession(websiteId, { + session_uuid, + hostname, + browser, + os, + screen, + language, + country, + device, + }); + } catch (e) { + if (!e.message.toLowerCase().includes('unique constraint')) { + throw e; + } + } + } + } else { + session = { + session_id: sessionId, + session_uuid, + hostname, + browser, + os, + screen, + language, + country, + device, + }; + } return { website_id: websiteId, diff --git a/pages/api/collect.js b/pages/api/collect.js index f253d09e..66e9a8a4 100644 --- a/pages/api/collect.js +++ b/pages/api/collect.js @@ -1,95 +1,5 @@ -const { Resolver } = require('dns').promises; -import isbot from 'isbot'; -import ipaddr from 'ipaddr.js'; -import { createToken, unauthorized, send, badRequest, forbidden } from 'next-basics'; -import { savePageView, saveEvent } from 'queries'; -import { useCors, useSession } from 'lib/middleware'; -import { getJsonBody, getIpAddress } from 'lib/request'; -import { secret, uuid } from 'lib/crypto'; +import { forbidden } from 'next-basics'; export default async (req, res) => { - await useCors(req, res); - - if (isbot(req.headers['user-agent']) && !process.env.DISABLE_BOT_CHECK) { - return unauthorized(res); - } - - const ignoreIps = process.env.IGNORE_IP; - const ignoreHostnames = process.env.IGNORE_HOSTNAME; - - if (ignoreIps || ignoreHostnames) { - const ips = []; - - if (ignoreIps) { - ips.push(...ignoreIps.split(',').map(n => n.trim())); - } - - if (ignoreHostnames) { - const resolver = new Resolver(); - const promises = ignoreHostnames - .split(',') - .map(n => resolver.resolve4(n.trim()).catch(() => {})); - - await Promise.all(promises).then(resolvedIps => { - ips.push(...resolvedIps.filter(n => n).flatMap(n => n)); - }); - } - - const clientIp = getIpAddress(req); - - const blocked = ips.find(ip => { - if (ip === clientIp) return true; - - // CIDR notation - if (ip.indexOf('/') > 0) { - const addr = ipaddr.parse(clientIp); - const range = ipaddr.parseCIDR(ip); - - if (addr.kind() === range[0].kind() && addr.match(range)) return true; - } - - return false; - }); - - if (blocked) { - return forbidden(res); - } - } - - await useSession(req, res); - - const { - session: { website_id, session }, - } = req; - - const { type, payload } = getJsonBody(req); - - let { url, referrer, event_name, event_data } = payload; - - if (process.env.REMOVE_TRAILING_SLASH) { - url = url.replace(/\/$/, ''); - } - - const event_uuid = uuid(); - - if (type === 'pageview') { - await savePageView(website_id, { session, url, referrer }); - } else if (type === 'event') { - await saveEvent(website_id, { - session, - event_uuid, - url, - event_name, - event_data, - }); - } else { - return badRequest(res); - } - - const token = createToken( - { website_id, session_id: session.session_id, session_uuid: session.session_uuid }, - secret(), - ); - - return send(res, token); + return forbidden(res); };