feat: serve local files
This commit is contained in:
parent
89666ac4c7
commit
ba9912d5ad
@ -21,11 +21,10 @@ export function setDefaultHttpRequest(): void {
|
||||
if (httpRequestBox) {
|
||||
// Only set default if the textarea is empty
|
||||
if (!httpRequestBox.value.trim()) {
|
||||
const defaultRequest = `GET /index.html HTTP/1.1
|
||||
Host: example.com
|
||||
User-Agent: NostrClient/1.0
|
||||
Accept: text/html,application/xhtml+xml,application/xml
|
||||
Connection: keep-alive
|
||||
const defaultRequest = `GET /hello.txt HTTP/1.1
|
||||
Host: localhost
|
||||
User-Agent: Nostr-HTTP-Client
|
||||
Accept: text/plain
|
||||
|
||||
`;
|
||||
httpRequestBox.value = defaultRequest;
|
||||
@ -51,16 +50,16 @@ export function processTags(tags: string[][]): string[][] {
|
||||
if (!tags || !Array.isArray(tags)) {
|
||||
return tags;
|
||||
}
|
||||
|
||||
|
||||
// Make a deep copy of tags to avoid modifying the original
|
||||
const processedTags = JSON.parse(JSON.stringify(tags));
|
||||
|
||||
|
||||
for (let i = 0; i < processedTags.length; i++) {
|
||||
const tag = processedTags[i];
|
||||
if (!tag || !Array.isArray(tag) || tag.length < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Convert npub in "p" tags to hex pubkeys
|
||||
if (tag[0] === 'p' && typeof tag[1] === 'string' && tag[1].startsWith('npub')) {
|
||||
try {
|
||||
@ -72,13 +71,13 @@ export function processTags(tags: string[][]): string[][] {
|
||||
// Silent error handling
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Ensure expiration tag value is a string
|
||||
if (tag[0] === 'expiration' && tag[1]) {
|
||||
processedTags[i][1] = String(tag[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return processedTags;
|
||||
}
|
||||
|
||||
@ -91,7 +90,7 @@ export function standardizeEvent(event: Record<string, unknown>): NostrEvent {
|
||||
if (!event || typeof event !== 'object') {
|
||||
throw new Error('Invalid event: not an object');
|
||||
}
|
||||
|
||||
|
||||
// Type assertions needed for raw object properties
|
||||
return {
|
||||
id: String(event.id || ''),
|
||||
|
1
server/public/goodbye.txt
Normal file
1
server/public/goodbye.txt
Normal file
@ -0,0 +1 @@
|
||||
Goodbye!
|
6
server/public/hello.txt
Normal file
6
server/public/hello.txt
Normal file
@ -0,0 +1,6 @@
|
||||
Hello from the Nostr HTTP Server!
|
||||
|
||||
This is a sample file that can be served by the server.
|
||||
You can request this file by making a request to /hello.txt
|
||||
|
||||
The server will read this file from the local filesystem and return its contents.
|
@ -7,9 +7,11 @@ import NDK from '@nostr-dev-kit/ndk';
|
||||
import { NDKUser, NDKEvent, NDKFilter, NDKPrivateKeySigner, NDKSubscription } from '@nostr-dev-kit/ndk';
|
||||
import express from 'express';
|
||||
import { createServer } from 'http';
|
||||
import { ServerConfig, HttpRequest, RateLimitConfig, RateLimitState } from './types';
|
||||
import { ServerConfig, HttpRequest, RateLimitConfig, RateLimitState } from './types.js';
|
||||
import WebSocket from 'ws';
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
// Custom subscription interface for our WebSocket implementation
|
||||
interface CustomSubscription {
|
||||
@ -198,7 +200,7 @@ export class NostrHttpServer {
|
||||
*/
|
||||
private async publishToRelays(event: any): Promise<Map<string, { success: boolean; message: string }>> {
|
||||
const results = new Map<string, { success: boolean; message: string }>();
|
||||
const publishPromises = this.config.relayUrls.map(async (relayUrl) => {
|
||||
const publishPromises = this.config.relayUrls.map(async (relayUrl: string) => {
|
||||
try {
|
||||
const result = await this.publishToRelay(event, relayUrl);
|
||||
results.set(relayUrl, result);
|
||||
@ -839,7 +841,35 @@ export class NostrHttpServer {
|
||||
* @param request The HTTP request to execute
|
||||
*/
|
||||
private async executeHttpRequest(request: HttpRequest): Promise<string> {
|
||||
// Return a simple Hello World response instead of executing the actual request
|
||||
// Check if the request is for a file in the public directory
|
||||
const publicDir = path.join(process.cwd(), 'public');
|
||||
const requestedPath = path.join(publicDir, request.path.replace(/^\//, ''));
|
||||
|
||||
// log the requested path
|
||||
console.log('requestedPath', requestedPath);
|
||||
console.log('publicDir', publicDir);
|
||||
|
||||
try {
|
||||
// Check if the file exists and is within the public directory
|
||||
if (fs.existsSync(requestedPath)) {
|
||||
const filePath = publicDir + request.path;
|
||||
|
||||
const fileContent = fs.readFileSync(filePath, 'utf8');
|
||||
const contentType = this.getContentType(filePath);
|
||||
|
||||
// Build response string with file content
|
||||
return `HTTP/1.1 200 OK
|
||||
Content-Type: ${contentType}
|
||||
Content-Length: ${fileContent.length}
|
||||
|
||||
${fileContent}`;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error reading file:', error);
|
||||
// If there's an error reading the file, fall back to the default response
|
||||
}
|
||||
|
||||
// Return the default response if no file is found or there's an error
|
||||
const responseBody = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@ -878,13 +908,33 @@ export class NostrHttpServer {
|
||||
</html>`;
|
||||
|
||||
// Build response string
|
||||
let responseStr = `HTTP/1.1 200 OK
|
||||
return `HTTP/1.1 200 OK
|
||||
Content-Type: text/html
|
||||
Content-Length: ${responseBody.length}
|
||||
|
||||
${responseBody}`;
|
||||
}
|
||||
|
||||
return responseStr;
|
||||
/**
|
||||
* Get the content type for a file based on its extension
|
||||
* @param filePath The path to the file
|
||||
* @returns The content type string
|
||||
*/
|
||||
private getContentType(filePath: string): string {
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const contentTypes: Record<string, string> = {
|
||||
'.txt': 'text/plain',
|
||||
'.html': 'text/html',
|
||||
'.css': 'text/css',
|
||||
'.js': 'text/javascript',
|
||||
'.json': 'application/json',
|
||||
'.png': 'image/png',
|
||||
'.jpg': 'image/jpeg',
|
||||
'.jpeg': 'image/jpeg',
|
||||
'.gif': 'image/gif',
|
||||
'.svg': 'image/svg+xml'
|
||||
};
|
||||
return contentTypes[ext] || 'text/plain';
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user