-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
139 lines (115 loc) · 3.81 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import express from 'express';
import cors from 'cors';
import fetch from 'node-fetch';
const app = express();
const port = process.env.PORT || 3001;
// Middleware
app.use(cors());
app.use(express.json());
// Helper function to process hex input
function processHexInput(input) {
const hexString = input.startsWith('0x') ? input.slice(2) : input;
return Buffer.from(hexString, 'hex');
}
// Helper function to detect if content is text
function isTextContent(buffer) {
// Check if the buffer contains valid UTF-8 text
try {
// Convert buffer to string and back to buffer
const text = buffer.toString('utf8');
const backToBuffer = Buffer.from(text, 'utf8');
// If the buffers match and don't contain control characters (except newline and tab)
return buffer.equals(backToBuffer) &&
!buffer.some(byte => (byte < 32 && byte !== 9 && byte !== 10) || byte === 127);
} catch {
return false;
}
}
// Helper function to get content type
function detectContentType(buffer) {
// Check for common file signatures
if (buffer.length >= 4) {
// PDF signature
if (buffer[0] === 0x25 && buffer[1] === 0x50 && buffer[2] === 0x44 && buffer[3] === 0x46) {
return 'application/pdf';
}
// JPEG signature
if (buffer[0] === 0xFF && buffer[1] === 0xD8 && buffer[2] === 0xFF) {
return 'image/jpeg';
}
// PNG signature
if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4E && buffer[3] === 0x47) {
return 'image/png';
}
}
// Check if it's text content
if (isTextContent(buffer)) {
return 'text/plain';
}
// Default to binary
return 'application/octet-stream';
}
// Main bundle route
app.get('/bundle/:txHash/:index', async (req, res) => {
try {
const { txHash, index } = req.params;
// Validate index is a number
const envelopeIndex = parseInt(index, 10);
if (isNaN(envelopeIndex)) {
return res.status(400).json({ error: 'Invalid index parameter' });
}
// Fetch bundle data
const response = await fetch(`https://bundler.wvm.network/v1/envelopes/${txHash}`);
if (!response.ok) {
return res.status(response.status).json({
error: `Failed to fetch bundle data: ${response.statusText}`
});
}
const data = await response.json();
// Validate envelope exists at index
if (!data.envelopes?.[envelopeIndex]) {
return res.status(404).json({
error: `No envelope found at index ${envelopeIndex}`
});
}
const envelope = data.envelopes[envelopeIndex];
// Get input
const input = envelope.input;
if (!input) {
return res.status(400).json({ error: 'No input data found in envelope' });
}
// Get content type tag if it exists (case-insensitive)
const contentTypeTag = envelope.tags?.find(tag => tag.name.toLowerCase() === 'content-type');
// Process the input data
let processedData;
try {
processedData = processHexInput(input);
} catch (error) {
return res.status(400).json({
error: `Failed to process input data: ${error.message}`
});
}
// Set response headers
res.set({
'Content-Type': contentTypeTag?.value || detectContentType(processedData),
'Content-Length': processedData.length,
'Cache-Control': 'public, max-age=31536000'
});
// Send the processed data
return res.send(processedData);
} catch (error) {
console.error('Error processing bundle request:', error);
return res.status(500).json({
error: 'Internal server error while processing bundle'
});
}
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something broke!' });
});
// Start server
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});