115 lines
3.7 KiB
JavaScript
115 lines
3.7 KiB
JavaScript
import {PutObjectCommand, S3Client} from "@aws-sdk/client-s3";
|
|
import cors from 'cors'
|
|
import crypto from "crypto";
|
|
import {sql} from "./db.js";
|
|
import {decodeBase62} from "../web/src/common.js";
|
|
|
|
const APP_URL = process.env.DEXORDER_APP_URL;
|
|
const SNAPSHOT_URL = process.env.DEXORDER_SNAPSHOT_URL;
|
|
|
|
const S3_BUCKET = process.env.DEXORDER_SNAPSHOT_S3_BUCKET_NAME;
|
|
const S3_ACCESS_KEY_ID = process.env.DEXORDER_SNAPSHOT_S3_ACCESS_KEY_ID;
|
|
const S3_SECRET_ACCESS_KEY = process.env.DEXORDER_SNAPSHOT_S3_SECRET_ACCESS_KEY;
|
|
const S3_ENDPOINT = process.env.DEXORDER_SNAPSHOT_S3_ENDPOINT; // e.g., 'https://<ACCOUNT_ID>.r2.cloudflarestorage.com/'
|
|
|
|
const s3 = new S3Client({
|
|
region: "auto",
|
|
endpoint: S3_ENDPOINT,
|
|
credentials: {
|
|
accessKeyId: S3_ACCESS_KEY_ID,
|
|
secretAccessKey: S3_SECRET_ACCESS_KEY,
|
|
}
|
|
});
|
|
|
|
|
|
function imageFilename(code) {
|
|
return 'share_' + code + '.png';
|
|
}
|
|
|
|
|
|
async function saveSnapshot(code, snapshot) {
|
|
await s3.send(new PutObjectCommand({
|
|
Bucket: S3_BUCKET,
|
|
Key: imageFilename(code),
|
|
Body: snapshot,
|
|
ContentType: 'image/png',
|
|
ACL: 'public-read', // or private, depending on your needs
|
|
}))
|
|
}
|
|
|
|
|
|
export async function share(socket, data, snapshot, respond) {
|
|
try {
|
|
const result = await sql('insert into sharedata (data) values ($1) returning id', data)
|
|
if (result.rowCount !== 1) {
|
|
console.error('insertion of sharedata failed', result)
|
|
respond(null)
|
|
}
|
|
const code = encodeURIComponent(result.rows[0].id)
|
|
respond(code);
|
|
saveSnapshot(code, snapshot).catch(e => console.error('save snapshot error', e))
|
|
}
|
|
catch (e) {
|
|
console.error('share error', e)
|
|
respond(null)
|
|
}
|
|
}
|
|
|
|
|
|
export async function shared(socket, code, respond) {
|
|
try {
|
|
const id = decodeBase62(code)
|
|
const result = await sql('select data from sharedata where id = $1', id)
|
|
if (result.rowCount !== 1) {
|
|
console.error('could not find share data', code)
|
|
respond(null)
|
|
}
|
|
const data = result.rows[0].data
|
|
console.log('shared data', data)
|
|
respond(data)
|
|
}
|
|
catch (e) {
|
|
console.error('shared error', e)
|
|
respond(null)
|
|
}
|
|
}
|
|
|
|
|
|
export function initSnapShare(app) {
|
|
// this URL is called by the frontend to upload order data and a snapshot image for use on a share page
|
|
app.post('/sharecode', cors({origin: process.env.DEXORDER_APP_URL}),
|
|
(req, res) => {
|
|
const chunks = [];
|
|
req.on('data', chunk => chunks.push(chunk))
|
|
req.on('error', (err) => res.status(500).send('Error reading body'))
|
|
req.on('end', () => {
|
|
const filename = crypto.randomUUID() + '.png';
|
|
const body = Buffer.concat(chunks);
|
|
s3.send(new PutObjectCommand({
|
|
Bucket: S3_BUCKET,
|
|
Key: filename,
|
|
Body: body,
|
|
ContentType: 'image/png',
|
|
ACL: 'public-read', // or private, depending on your needs
|
|
})).then(sent => {
|
|
res.send(filename)
|
|
}).catch(err => {
|
|
console.log('upload error', err)
|
|
res.status(500).send('error')
|
|
});
|
|
});
|
|
});
|
|
|
|
// this link returns a "share page" that shows the snapshot of the trade setup then redirects
|
|
// to the order page with the trade data loaded from the URL
|
|
app.get('/share/:code', (req, res) => {
|
|
const code = req.params.code;
|
|
const data = {
|
|
imageUrl: SNAPSHOT_URL + '/' + imageFilename(code),
|
|
redirectUrl: APP_URL + '/shared/' + code
|
|
};
|
|
res.render('share', data);
|
|
});
|
|
|
|
}
|