WF test using selhst icons
This commit is contained in:
@@ -10,7 +10,7 @@ steps:
|
||||
- name: publish-next-agent
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
settings:
|
||||
repo: ryuupendragon/caddy-test
|
||||
repo: ryuupendragon/icons-test
|
||||
dockerfile: Dockerfile
|
||||
platforms: linux/amd64,linux/arm64/v8
|
||||
tag: latest
|
||||
|
||||
15
Dockerfile
15
Dockerfile
@@ -1,10 +1,11 @@
|
||||
FROM caddy:2.10.0-builder AS builder
|
||||
FROM node:18-alpine
|
||||
WORKDIR /app
|
||||
|
||||
RUN xcaddy build \
|
||||
--with github.com/hslatman/caddy-crowdsec-bouncer/http \
|
||||
--with github.com/hslatman/caddy-crowdsec-bouncer/layer4 \
|
||||
--with github.com/hslatman/caddy-crowdsec-bouncer/appsec
|
||||
COPY package.json ./
|
||||
RUN npm install
|
||||
|
||||
FROM caddy:2.10.0
|
||||
COPY server.js .
|
||||
|
||||
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
|
||||
EXPOSE 4050
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
13
package.json
Normal file
13
package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "test-repo",
|
||||
"version": "1.0.0",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "node server.js"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
"node-fetch": "^3.3.0"
|
||||
}
|
||||
}
|
||||
89
server.js
Normal file
89
server.js
Normal file
@@ -0,0 +1,89 @@
|
||||
import express from 'express'
|
||||
import fetch from 'node-fetch'
|
||||
import path from 'path'
|
||||
|
||||
const app = express()
|
||||
const PORT = 4050
|
||||
const CDN_ROOT = 'https://cdn.jsdelivr.net/gh/selfhst/icons'
|
||||
const CDN_PATH = 'svg'
|
||||
|
||||
async function fileExists(url) {
|
||||
try {
|
||||
const resp = await fetch(url, { method: 'HEAD' });
|
||||
return resp.ok;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchAndPipe(url, res) {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) return res.status(404).send('File not found');
|
||||
res.type(path.extname(url).slice(1));
|
||||
response.body.pipe(res);
|
||||
}
|
||||
|
||||
app.get('/*', async (req, res) => {
|
||||
const urlPath = req.path;
|
||||
const extMatch = urlPath.match(/\.(\w+)$/);
|
||||
if (!extMatch)
|
||||
return res.status(404).send('File extension missing');
|
||||
|
||||
const ext = extMatch[1].toLowerCase();
|
||||
if (!['png', 'webp', 'svg'].includes(ext))
|
||||
return res.status(404).send('Format not supported');
|
||||
|
||||
const filename = urlPath.slice(1);
|
||||
const lowerFilename = filename.toLowerCase();
|
||||
|
||||
const isSuffix = lowerFilename.endsWith('-light.svg') || lowerFilename.endsWith('-dark.svg');
|
||||
|
||||
if (isSuffix) {
|
||||
return fetchAndPipe(`${CDN_ROOT}/${CDN_PATH}/${filename}`, res);
|
||||
}
|
||||
|
||||
let mainUrl;
|
||||
if (ext === 'png') {
|
||||
mainUrl = `${CDN_ROOT}/png/${filename}`;
|
||||
} else if (ext === 'webp') {
|
||||
mainUrl = `${CDN_ROOT}/webp/${filename}`;
|
||||
} else if (ext === 'svg') {
|
||||
mainUrl = `${CDN_ROOT}/svg/${filename}`;
|
||||
} else {
|
||||
mainUrl = null;
|
||||
}
|
||||
|
||||
const hasColor = !!req.query['color'] && req.query['color'].trim() !== '';
|
||||
|
||||
if (ext === 'svg') {
|
||||
if (hasColor) {
|
||||
const baseName = filename.replace(/\.(png|webp|svg)$/, '');
|
||||
const suffixUrl = `${CDN_ROOT}/${CDN_PATH}/${baseName}-light.svg`;
|
||||
if (await fileExists(suffixUrl)) {
|
||||
let svgContent = await fetch(suffixUrl).then(r => r.text());
|
||||
const color = req.query['color'].startsWith('#') ? req.query['color'] : `#${req.query['color']}`;
|
||||
svgContent = svgContent
|
||||
.replace(/style="[^"]*fill:\s*#fff[^"]*"/gi, (match) => {
|
||||
console.log('Replacing style fill:', match);
|
||||
return match.replace(/fill:\s*#fff/gi, `fill:${color}`);
|
||||
})
|
||||
.replace(/fill="#fff"/gi, `fill="${color}"`);
|
||||
return res.type('image/svg+xml').send(svgContent);
|
||||
} else {
|
||||
return fetchAndPipe(mainUrl, res);
|
||||
}
|
||||
} else {
|
||||
return fetchAndPipe(mainUrl, res);
|
||||
}
|
||||
} else {
|
||||
// PNG/WebP: serve directly
|
||||
return fetchAndPipe(mainUrl, res);
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
res.send('Self-hosted icon server');
|
||||
});
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Listening on port ${PORT}`);
|
||||
});
|
||||
Reference in New Issue
Block a user