zrcadlo https://github.com/atscan/atscan
blob proxy
This commit is contained in:
rodič
f70768a75e
revize
c71d48bdf2
|
@ -0,0 +1,96 @@
|
|||
import { ATScan } from "./lib/atscan.js";
|
||||
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
|
||||
import { oakCors } from "https://deno.land/x/cors/mod.ts";
|
||||
import { join } from "https://deno.land/std@0.192.0/path/posix.ts";
|
||||
import { exists } from "https://deno.land/std@0.193.0/fs/exists.ts";
|
||||
import { ensureDir } from "https://deno.land/std@0.192.0/fs/ensure_dir.ts";
|
||||
import { Sha256 } from "https://deno.land/std@0.119.0/hash/sha256.ts";
|
||||
|
||||
//import * as zstd from "https://deno.land/x/zstd_wasm/deno/zstd.ts";
|
||||
//await zstd.init();
|
||||
|
||||
const ats = new ATScan();
|
||||
await ats.init();
|
||||
ats.startDaemon();
|
||||
|
||||
const HTTP_PORT = ats.env.PORT || 6680;
|
||||
const app = new Application();
|
||||
const router = new Router();
|
||||
|
||||
function perf(ctx) {
|
||||
if (ctx.request.url.toString().startsWith("http://localhost:")) {
|
||||
return null;
|
||||
}
|
||||
console.log(
|
||||
`[${HTTP_PORT}] GET ${ctx.request.url} [${
|
||||
performance.now() - ctx.perf
|
||||
}ms] ${ctx.request.headers.get("user-agent")}`,
|
||||
);
|
||||
}
|
||||
|
||||
router
|
||||
.get("/:did/:cid", async (ctx) => {
|
||||
const { did, cid } = ctx.params;
|
||||
if (!cid || !cid.startsWith("baf")) {
|
||||
return ctx.status = 404;
|
||||
}
|
||||
const item = await ats.db.did.findOne({ did });
|
||||
if (!item || !item.pds) {
|
||||
return ctx.status = 404;
|
||||
}
|
||||
|
||||
let index = null;
|
||||
let body = null;
|
||||
const blobDir = join(ats.env.ATSCAN_DB_PATH, "blob", did);
|
||||
await ensureDir(blobDir);
|
||||
const cacheIndexFn = join(blobDir, `${cid}.json`);
|
||||
const cacheFn = join(blobDir, `${cid}.blob`);
|
||||
|
||||
if (!await exists(cacheIndexFn)) {
|
||||
const src = `${
|
||||
item.pds[0]
|
||||
}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}`;
|
||||
const blobRes = await fetch(src);
|
||||
if (!blobRes.ok) {
|
||||
return ctx.status = 404;
|
||||
}
|
||||
body = new Uint8Array(await blobRes.arrayBuffer());
|
||||
//const compressed = zstd.compress(body);
|
||||
index = {
|
||||
src,
|
||||
did,
|
||||
cid,
|
||||
hash: new Sha256().update(body).hex(),
|
||||
time: new Date(),
|
||||
size: body.length,
|
||||
//sizeCompressed: compressed.length,
|
||||
headers: {
|
||||
"content-length": blobRes.headers.get("content-length"),
|
||||
"content-type": blobRes.headers.get("content-type"),
|
||||
},
|
||||
};
|
||||
await Deno.writeTextFile(cacheIndexFn, JSON.stringify(index, null, 2));
|
||||
await Deno.writeFile(cacheFn, body);
|
||||
} else {
|
||||
index = JSON.parse(await Deno.readTextFile(cacheIndexFn));
|
||||
//body = zstd.decompress(await Deno.readFile(cacheFn));
|
||||
body = await Deno.readFile(cacheFn);
|
||||
}
|
||||
|
||||
for (const headerKey of Object.keys(index.headers)) {
|
||||
ctx.response.headers.set(headerKey, index.headers[headerKey]);
|
||||
}
|
||||
ctx.response.body = body;
|
||||
perf(ctx);
|
||||
});
|
||||
|
||||
app.use(oakCors()); // Enable CORS for All Routes
|
||||
app.use(async (ctx, next) => {
|
||||
ctx.perf = performance.now();
|
||||
await next();
|
||||
});
|
||||
app.use(router.routes());
|
||||
|
||||
app.listen({ port: HTTP_PORT });
|
||||
|
||||
console.log(`ATScan API started at port ${HTTP_PORT}`);
|
|
@ -55,6 +55,7 @@ if (Number(ats.env.PORT) === 6677) {
|
|||
|
||||
const HTTP_PORT = ats.env.PORT || 6677;
|
||||
const app = new Application();
|
||||
const router = new Router();
|
||||
|
||||
function perf(ctx) {
|
||||
if (ctx.request.url.toString().startsWith("http://localhost:")) {
|
||||
|
@ -67,8 +68,6 @@ function perf(ctx) {
|
|||
);
|
||||
}
|
||||
|
||||
const router = new Router();
|
||||
|
||||
function findPDSFed(item) {
|
||||
const ff = ats.ecosystem.data.federations.find((fed) => {
|
||||
if (fed.pds) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import Chart from '$lib/components/Chart.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
export let data;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ export const config = {
|
|||
name: 'ATScan',
|
||||
domain: 'atscan.net',
|
||||
api: 'https://api.atscan.net',
|
||||
blobApi: 'https://blob.atscan.net',
|
||||
web: 'https://atscan.net',
|
||||
git: 'https://github.com/atscan/atscan',
|
||||
status: 'https://status.gwei.cz/status/atscan',
|
||||
|
|
|
@ -195,7 +195,7 @@
|
|||
<th class="text-right">Avatar</th>
|
||||
<td
|
||||
><img
|
||||
src={`${item.pds[0]}/xrpc/com.atproto.sync.getBlob?did=${item.did}&cid=${item.repo.profile.avatar.ref.$link}`}
|
||||
src={`${data.config.blobApi}/${item.did}/${item.repo.profile.avatar.ref.$link}`}
|
||||
class="w-40"
|
||||
/></td
|
||||
>
|
||||
|
@ -206,7 +206,7 @@
|
|||
<th class="text-right">Banner</th>
|
||||
<td
|
||||
><img
|
||||
src={`${item.pds[0]}/xrpc/com.atproto.sync.getBlob?did=${item.did}&cid=${item.repo.profile.banner.ref.$link}`}
|
||||
src={`${data.config.blobApi}/${item.did}/${item.repo.profile.banner.ref.$link}`}
|
||||
class="w-40"
|
||||
/></td
|
||||
>
|
||||
|
|
|
@ -58,6 +58,11 @@ module.exports = {
|
|||
env: {
|
||||
PORT: 6678
|
||||
}
|
||||
}, {
|
||||
name: "atscan-api-blob",
|
||||
script: "./backend/api-blob.js",
|
||||
interpreter: "deno",
|
||||
interpreterArgs: "run --unstable --allow-net --allow-read --allow-write --allow-env --allow-sys",
|
||||
}, {
|
||||
name: "atscan-worker",
|
||||
script: "./backend/repo-worker.js",
|
||||
|
|
Načítá se…
Odkázat v novém úkolu