feat(vpn): VPN on-demand Tailscale + agent studioE5 standalone
- Agent studioE5 standalone en Go (console + systray) - VPN on-demand via tailscaled + tailscale up (authkey Headscale) - Resolver/serveur dans le tailnet studioe5 - Caddy on-demand TLS pour les instances - Nouveaux endpoints serveur /api/internal/send-to-node - Suppression des anciens binaires edubox-agent - Suivi dans SUIVI_VPN_ONDEMAND.md
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import zlib
|
||||
import struct
|
||||
|
||||
|
||||
def png_chunk(chunk_type: bytes, data: bytes) -> bytes:
|
||||
return (
|
||||
struct.pack(">I", len(data))
|
||||
+ chunk_type
|
||||
+ data
|
||||
+ struct.pack(">I", zlib.crc32(chunk_type + data) & 0xFFFFFFFF)
|
||||
)
|
||||
|
||||
|
||||
def create_png(width: int, height: int, pixels: list) -> bytes:
|
||||
"""Create a PNG from a 2D list of (R, G, B) tuples."""
|
||||
raw = bytearray()
|
||||
for row in pixels:
|
||||
raw.append(0) # no filter
|
||||
for r, g, b in row:
|
||||
raw.extend((r, g, b))
|
||||
compressed = zlib.compress(bytes(raw), 9)
|
||||
|
||||
ihdr_data = struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0)
|
||||
ihdr = png_chunk(b"IHDR", ihdr_data)
|
||||
idat = png_chunk(b"IDAT", compressed)
|
||||
iend = png_chunk(b"IEND", b"")
|
||||
|
||||
return b"\x89PNG\r\n\x1a\n" + ihdr + idat + iend
|
||||
|
||||
|
||||
BLUE = (37, 99, 235)
|
||||
WHITE = (255, 255, 255)
|
||||
SIZE = 64
|
||||
|
||||
pixels = []
|
||||
for y in range(SIZE):
|
||||
row = []
|
||||
for x in range(SIZE):
|
||||
dx = x - SIZE // 2
|
||||
dy = y - SIZE // 2
|
||||
dist = (dx * dx + dy * dy) ** 0.5
|
||||
if dist < SIZE * 0.25:
|
||||
row.append(WHITE)
|
||||
else:
|
||||
row.append(BLUE)
|
||||
pixels.append(row)
|
||||
|
||||
with open("icon.png", "wb") as f:
|
||||
f.write(create_png(SIZE, SIZE, pixels))
|
||||
|
||||
print("Generated icon.png")
|
||||
Reference in New Issue
Block a user