diff --git a/.dockerignore b/.dockerignore index d754dc0..5ca25e5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,3 +2,4 @@ node_modules .github build +cache diff --git a/.gitignore b/.gitignore index ad22606..facc493 100644 --- a/.gitignore +++ b/.gitignore @@ -174,4 +174,6 @@ dist # Finder (MacOS) folder config .DS_Store -build \ No newline at end of file +build +cache + diff --git a/.prettierrc b/.prettierrc index bc84c45..f6957bf 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,6 @@ { "printWidth": 120, "useTabs": false, - "tabWidth": 2 + "tabWidth": 2, + "singleQuote": true } diff --git a/src/drive.ts b/src/drive.ts index dc5f558..d85a530 100644 --- a/src/drive.ts +++ b/src/drive.ts @@ -3,25 +3,17 @@ import debug from 'debug'; import NodeCache from 'node-cache'; import { Drive } from './types.js'; import uniqBy from 'lodash/uniqBy.js'; -import { SINGLE_SITE } from './env.js'; +import { DRIVE_CACHE_TTL, DRIVE_REFRESH_TIME, NOSTR_DEFAULT_RELAYS, SINGLE_SITE } from './env.js'; import { nip19 } from 'nostr-tools'; import { AddressPointer } from 'nostr-tools/nip19'; -const driveCache = new NodeCache({ stdTTL: 60 * 60 }); // 5min for development +const driveCache = new NodeCache({ stdTTL: DRIVE_CACHE_TTL }); const log = debug('web:drive:nostr'); -export const defaultRelays = [ - 'wss://nostrue.com', - 'wss://relay.damus.io', - //"wss://nostr.wine", - 'wss://nos.lol', - // "wss://nostr-pub.wellorder.net", -]; - // TODO use relays from naddr const ndk = new NDK({ - explicitRelayUrls: defaultRelays, + explicitRelayUrls: NOSTR_DEFAULT_RELAYS, }); ndk.connect(); @@ -100,7 +92,7 @@ export const readDrive = async ( const event = await ndk.fetchEvent( filter, {}, - NDKRelaySet.fromRelayUrls(relays?.concat(defaultRelays) || defaultRelays, ndk), + NDKRelaySet.fromRelayUrls(relays?.concat(NOSTR_DEFAULT_RELAYS) || NOSTR_DEFAULT_RELAYS, ndk), ); log('fetch finsihed'); @@ -124,5 +116,5 @@ if (SINGLE_SITE) { } else { // Load all drives into the cache fetchAllDrives(); - setInterval(() => fetchAllDrives(), 60000); + setInterval(() => fetchAllDrives(), DRIVE_REFRESH_TIME); } diff --git a/src/env.ts b/src/env.ts index 6ec9e4b..d4f3109 100644 --- a/src/env.ts +++ b/src/env.ts @@ -1,2 +1,14 @@ -export const SINGLE_SITE = process.env.SINGLE_SITE; export const PORT = process.env.PORT || 3010; + +export const SINGLE_SITE = process.env.SINGLE_SITE; +export const FOLDER_LISTING = (process.env.FOLDER_LISTING || 'true') === 'true'; + +export const DRIVE_PRELOAD = (process.env.DRIVE_PRELOAD || 'false') === 'true'; +export const DRIVE_REFRESH_TIME = parseInt(process.env.DRIVE_REFRESH_TIME || '300', 10) * 1000; // 5min +export const DRIVE_CACHE_TTL = parseInt(process.env.DRIVE_CACHE_TTL || '3600', 10); // 1h + +export const CDN_CACHE_DIR = process.env.CDN_CACHE_DIR || './cache'; +export const CDN_MAX_LOCAL_CACHE_SIZE = parseInt(process.env.CDN_MAX_LOCAL_CACHE_SIZE || '', 100000); // 100KB +export const CDN_ADDITIONAL_SERVERS = (process.env.CDN_ADDITIONAL_SERVERS || 'https://cdn.hzrd149.com,https://cdn.satellite.earth').split(','); + +export const NOSTR_DEFAULT_RELAYS = (process.env.NOSTR_DEFAULT_RELAYS || 'wss://nostrue.com,wss://relay.damus.io,wss://nos.lol').split(','); diff --git a/src/index.ts b/src/index.ts index 064f05e..94603e5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,12 +5,19 @@ import Router from '@koa/router'; import { nip19 } from 'nostr-tools'; import { AddressPointer } from 'nostr-tools/nip19'; import { Drive, FileMeta } from './types.js'; -import { defaultRelays, readDrive } from './drive.js'; +import { readDrive } from './drive.js'; import { searchCdn } from './cdn.js'; import { PassThrough } from 'stream'; import fs from 'node:fs'; import nodePath from 'path'; -import { PORT, SINGLE_SITE } from './env.js'; +import { + CDN_ADDITIONAL_SERVERS, + CDN_CACHE_DIR, + CDN_MAX_LOCAL_CACHE_SIZE, + FOLDER_LISTING, + PORT, + SINGLE_SITE, +} from './env.js'; import { appendSlashIfMissing, prefixSlashIfMissing, removeLeadingSlashes } from './utils.js'; const log = debug('web'); @@ -18,7 +25,6 @@ const app = new Koa(); const router = new Router(); // const cacheAdapter = new NDKCacheAdapterDexie({ dbName: "ndk-cache" }); -const additionalServers = ['https://cdn.hzrd149.com', 'https://cdn.satellite.earth']; const findFile = (drive: Drive, filePathToSearch: string): FileMeta | undefined => { const searchPath = prefixSlashIfMissing(filePathToSearch); @@ -30,9 +36,8 @@ const findFolderContents = (drive: Drive, filePathToSearch: string): FileMeta[] return drive.files.filter((f) => f.path.startsWith(searchPath)); }; -const cacheDir = './cache'; -if (!fs.existsSync(cacheDir)) { - fs.mkdirSync(cacheDir, { recursive: true }); +if (!fs.existsSync(CDN_CACHE_DIR)) { + fs.mkdirSync(CDN_CACHE_DIR, { recursive: true }); } // handle errors @@ -85,17 +90,17 @@ const serveStream = (ctx: Koa.ParameterizedContext, mimeType: string, src: NodeJ const serveDriveFile = async (ctx: Koa.ParameterizedContext, drive: Drive, fileMeta: FileMeta) => { const { hash, mimeType, size } = fileMeta; - const cacheFile = nodePath.join(cacheDir, hash); + const cacheFile = nodePath.join(CDN_CACHE_DIR, hash); if (fs.existsSync(cacheFile)) { log(`returning cached data for ${hash}`); const src = fs.createReadStream(cacheFile); serveStream(ctx, mimeType, src); } else { // lookup media sevrers for user -> ndk (optional) - const cdnSource = await searchCdn([...drive.servers, ...additionalServers], hash); + const cdnSource = await searchCdn([...drive.servers, ...CDN_ADDITIONAL_SERVERS], hash); if (cdnSource) { - if (size < 100000) { + if (size < CDN_MAX_LOCAL_CACHE_SIZE) { // if small file < 100KB, download and serve downloaded file await storeInCache(cdnSource, cacheFile); serveStream(ctx, mimeType, fs.createReadStream(cacheFile)); @@ -167,9 +172,12 @@ router.get('(.*)', async (ctx, next) => { const folder = findFolderContents(drive, searchPath); log('file not found in drive: ' + searchPath); ctx.status = 404; - ctx.set('Content-Type', 'text/html'); - const folderList = folder.map((f) => `
  • ${f.path}
  • `); - ctx.body = `

    Index of ${searchPath || '/'}

    `; + + if (FOLDER_LISTING) { + ctx.set('Content-Type', 'text/html'); + const folderList = folder.map((f) => `
  • ${f.path}
  • `); + ctx.body = `

    Index of ${searchPath || '/'}

    `; + } } } });