Revert back to old script
This commit is contained in:
parent
4c2bb9b812
commit
60ec3df42e
Binary file not shown.
|
@ -0,0 +1,12 @@
|
||||||
|
/srv/mirror/scripts/sync.sh archlinux &
|
||||||
|
/srv/mirror/scripts/sync.sh fedora &
|
||||||
|
/srv/mirror/scripts/sync.sh debian &
|
||||||
|
/srv/mirror/scripts/sync.sh ubuntu &
|
||||||
|
/srv/mirror/scripts/sync.sh kali &
|
||||||
|
/srv/mirror/scripts/sync.sh manjaro &
|
||||||
|
/srv/mirror/scripts/sync.sh raspbian &
|
||||||
|
/srv/mirror/scripts/sync.sh ubuntu_cd &
|
||||||
|
/srv/mirror/scripts/sync.sh kali_images &
|
||||||
|
/srv/mirror/scripts/sync.sh debian_cd &
|
||||||
|
/srv/mirror/scripts/sync.sh linux &
|
||||||
|
/srv/mirror/scripts/sync.sh gnu &
|
|
@ -0,0 +1,214 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Morgan's Mirror</title>
|
||||||
|
<link rel="icon" type="image/x-icon" href="static/favicon.ico">
|
||||||
|
<script src="static/tailwind.css"></script>
|
||||||
|
<script>
|
||||||
|
tailwind.config = {
|
||||||
|
darkMode: 'class'
|
||||||
|
}
|
||||||
|
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||||
|
// document.documentElement.classList.add('dark')
|
||||||
|
// if (localStorage.theme === 'dark') {
|
||||||
|
document.documentElement.classList.add('dark')
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.remove('dark')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans s3';
|
||||||
|
src: url("static/SourceSans3-Regular.woff2");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans 3';
|
||||||
|
src: url("static/SourceSans3-Bold.woff2");
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans 3';
|
||||||
|
src: url("static/SourceSans3-Semibold.woff2");
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans 3';
|
||||||
|
src: url("static/SourceSans3-Italic.woff2");
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'Source Sans 3';
|
||||||
|
}
|
||||||
|
.url {
|
||||||
|
font-style: italic;
|
||||||
|
color: rgb(86, 105, 151);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="text-gray-900 bg-gray-100 py-16 px-6 mx-auto max-w-5xl dark:bg-gray-900">
|
||||||
|
<!--
|
||||||
|
<div class="bg-red-500 text-white text-xl font-bold text-center mb-2 w-full fixed top-0 left-0">
|
||||||
|
MIRROR NOT MANAGED. SYNC JOB IS STILL RUNNING BUT MAY SHUT DOWN SOON.
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
<!-- <div class="bg-white text-black border border-black rounded text-lg font-light p-6 pt-7 m-6 w-80 fixed bottom-0 left-0 break-all" id="stopalert">
|
||||||
|
ISP's blocking/interruption of the network for high-bandwidth uploaders has caused frequent problems, disrupting the entire residential network.<br/>Rather than providing a slow and unreliable mirror, I thought it would be better to shut it down.<br/> I apologize for any confusion, and thank you for using my mirror.<br/>This mirror will be in sync as long as this page is alive.
|
||||||
|
<button onclick="document.getElementById('stopalert').remove();" class="absolute top-1 right-2">[X]</button>
|
||||||
|
</div> -->
|
||||||
|
<header class="mb-10 ml-2">
|
||||||
|
<h1 class="text-3xl font-bold mb-2 text-black dark:text-white">Welcome to Morgan's mirror archive!</h1>
|
||||||
|
<h2 class="text-xl text-gray-600 dark:text-gray-300 mb-1">Simple archiving server.</h2>
|
||||||
|
<h2 class="text-xl text-gray-600 dark:text-gray-300">This mirror is for archiving and NOT for public serving.</h2>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section class="mb-12">
|
||||||
|
<h2 class="dark:text-gray-200 text-2xl font-semibold mb-5 ml-2">Archive List</h2>
|
||||||
|
<div id="mirrorList" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-4">
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 md:col-span-2 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/archlinux"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">ArchLinux (x86_64)</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@archlinux@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span
|
||||||
|
class="url">rsync://mirrors.xtom.de/archlinux/</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/ubuntu"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">Ubuntu</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@ubuntu@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span
|
||||||
|
class="url">rsync://rsync.archive.ubuntu.com/ubuntu/</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/ubuntu-cd"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">Ubuntu Releases</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@ubuntu_cd@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span
|
||||||
|
class="url">rsync://releases.ubuntu.com/releases/</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/debian"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">Debian</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@debian@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span class="url">rsync://ftp.halifax.rwth-aachen.de/debian/</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/debian-cd"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">Debian Releases</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@debian_cd@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span class="url">rsync://ftp.lanet.kr/debian-cd/</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/kali"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">Kali Linux</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@kali@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span class="url">rsync://archive.kali.org/</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/kali-images"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">Kali Linux Images</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@kali_images@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span class="url">rsync://archive.kali.org/</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 md:col-span-2 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/manjaro"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">Manjaro</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@manjaro@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span
|
||||||
|
class="url">rsync://ftp.riken.jp/manjaro/</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 md:col-span-2 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/raspbian"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">Raspbian</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@raspbian@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span
|
||||||
|
class="url">rsync://archive.raspbian.org/archive/</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 md:col-span-2 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/fedora"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">Fedora</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@fedora@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span
|
||||||
|
class="url">rsync://dl.fedoraproject.org/fedora-enchilada/linux/</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 md:col-span-2 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/ubuntu-old"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">Ubuntu Releases (Old)</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@ubuntu_cd_old@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span
|
||||||
|
class="url">rsync://old-releases.ubuntu.com/releases/</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2"></div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 md:col-span-2 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/gnu"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">GNU</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@gnu@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span
|
||||||
|
class="url">rsync://ftp.gnu.org/gnu/</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 md:col-span-2 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/linux"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">Linux Kernel</a></h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">Last Updated: @@linux@@</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mt-1">Source: <span
|
||||||
|
class="url">rsync://kernel.org</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-800 col-span-1 md:col-span-2 shadow-lg rounded-lg p-5">
|
||||||
|
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/cd-image"
|
||||||
|
class="text-blue-900 hover:text-blue-600 dark:text-blue-300 dark:hover:text-blue-400">Image Files</a></h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="ml-2">
|
||||||
|
<h2 class="dark:text-gray-200 text-2xl font-semibold mb-4">Server Details</h2>
|
||||||
|
<p class="mb-2 text-gray-800 dark:text-gray-500"><strong>Location:</strong> Seoul, Korea</p>
|
||||||
|
<p class="mb-2 text-gray-800 dark:text-gray-500"><strong>Bandwidth:</strong> 100Mbps</p>
|
||||||
|
<p class="mb-2 text-gray-800 dark:text-gray-500"><strong>Storage size:</strong> 16TiB</p>
|
||||||
|
<p class="mb-2 text-gray-800 dark:text-gray-500"><strong>Sync delay:</strong> 4hrs </p>
|
||||||
|
<p class="mb-2 text-gray-800 dark:text-gray-500"><strong>Contact:</strong> <a href="mailto:mirror@morgan.kr">mirror@morgan.kr</a></p>
|
||||||
|
</section>
|
||||||
|
<button
|
||||||
|
class="fixed bottom-6 right-6 bg-blue-200 hover:bg-blue-300 text-blue-700 dark:bg-blue-800 dark:hover:bg-blue-600 dark:text-white w-10 h-10 rounded-full flex items-center justify-center"
|
||||||
|
onclick="toggleDarkMode()">
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="mt-10 text-center text-gray-600">
|
||||||
|
<a href="mailto:mirror@morgan.kr">©MORGAN.KR</a>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function toggleView(elementId) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
element.style.display = element.style.display === "none" ? "block" : "none";
|
||||||
|
}
|
||||||
|
function toggleDarkMode() {
|
||||||
|
if (document.documentElement.classList.contains('dark')) {
|
||||||
|
document.documentElement.classList.remove('dark');
|
||||||
|
localStorage.theme = 'light';
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
|
localStorage.theme = 'dark';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,131 +0,0 @@
|
||||||
BASE_DIR: /srv/mirror
|
|
||||||
|
|
||||||
# Any path under this must be in relative of BASE_DIR.
|
|
||||||
# Script doesnt do any kind of outbound check, so make sure to check all paths.
|
|
||||||
|
|
||||||
global:
|
|
||||||
scripts:
|
|
||||||
pre:
|
|
||||||
post:
|
|
||||||
log: logs/sync.log
|
|
||||||
log_dir: logs/
|
|
||||||
data_dir: pub/
|
|
||||||
sync:
|
|
||||||
- ALL
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
type: rsync
|
|
||||||
scripts:
|
|
||||||
pre:
|
|
||||||
fail:
|
|
||||||
- scripts/alert.sh
|
|
||||||
post:
|
|
||||||
- scripts/index.py ${config}
|
|
||||||
log: logs/${path}.log
|
|
||||||
delay: 4
|
|
||||||
rsync:
|
|
||||||
options: "-rtlHpv --chmod=D0755,F0644 --partial --hard-links --safe-links --stats --delete --delete-after --delay-updates --max-delete=70000"
|
|
||||||
exclude:
|
|
||||||
- ".*.??????"
|
|
||||||
- ".~tmp~/"
|
|
||||||
- "Packages*"
|
|
||||||
- "Sources*"
|
|
||||||
- "Release*"
|
|
||||||
- "*.links.tar.gz*"
|
|
||||||
- "/other"
|
|
||||||
- "/sources"
|
|
||||||
|
|
||||||
repos:
|
|
||||||
ARCHLINUX:
|
|
||||||
url: rsync://mirrors.xtom.de/archlinux/
|
|
||||||
name: "ArchLinux (x86_64)"
|
|
||||||
path: archlinux
|
|
||||||
|
|
||||||
UBUNTU:
|
|
||||||
url: rsync://rsync.archive.ubuntu.com/ubuntu/
|
|
||||||
name: "Ubuntu"
|
|
||||||
path: ubuntu
|
|
||||||
|
|
||||||
UBUNTU_CD:
|
|
||||||
url: rsync://releases.ubuntu.com/releases/
|
|
||||||
name: "Ubuntu Releases"
|
|
||||||
delay: 6
|
|
||||||
path: ubuntu_cd
|
|
||||||
|
|
||||||
UBUNTU_CD_OLD:
|
|
||||||
url: rsync://old-releases.ubuntu.com/releases/
|
|
||||||
name: "Ubuntu Releases (Old)"
|
|
||||||
delay: 12
|
|
||||||
path: ubuntu_cd_old
|
|
||||||
|
|
||||||
DEBIAN:
|
|
||||||
url: rsync://mirrors.xtom.jp/
|
|
||||||
type: ftpsync
|
|
||||||
name: Debian
|
|
||||||
path: debian
|
|
||||||
scripts:
|
|
||||||
|
|
||||||
# pre: scripts/pre_debian.sh
|
|
||||||
last_sync: "2023-10-12T10:58Z"
|
|
||||||
|
|
||||||
DEBIAN_CD:
|
|
||||||
url: rsync://ftp.lanet.kr/debian-cd/
|
|
||||||
delay: 6
|
|
||||||
name: "Debian CD"
|
|
||||||
path: debian_cd
|
|
||||||
|
|
||||||
FEDORA:
|
|
||||||
url: rsync://dl.fedoraproject.org/fedora-enchilada/linux/
|
|
||||||
name: "Fedora"
|
|
||||||
path: fedora
|
|
||||||
|
|
||||||
RASPBIAN:
|
|
||||||
url: rsync://archive.raspbian.org/archive/
|
|
||||||
delay: 6
|
|
||||||
name: "Raspbian"
|
|
||||||
path: raspbian
|
|
||||||
|
|
||||||
MANJARO:
|
|
||||||
url: rsync://ftp.riken.jp/manjaro/
|
|
||||||
name: Manjaro
|
|
||||||
path: manjaro
|
|
||||||
|
|
||||||
ARCHLINUXARM:
|
|
||||||
name: "ArchLinux (ARM)"
|
|
||||||
path: archlinuxarm
|
|
||||||
url: http://jp.mirror.archlinuxarm.org/
|
|
||||||
type: http
|
|
||||||
delay: 12
|
|
||||||
|
|
||||||
ASAHILINUX:
|
|
||||||
name: "AsahiLinux"
|
|
||||||
path: asahilinux
|
|
||||||
url: https://cdn.asahilinux.org/
|
|
||||||
type: http
|
|
||||||
delay: 12
|
|
||||||
|
|
||||||
GNU:
|
|
||||||
name: "GNU"
|
|
||||||
path: gnu
|
|
||||||
url: rsync://ftp.gnu.org/gnu/
|
|
||||||
delay: 12
|
|
||||||
|
|
||||||
LINUX:
|
|
||||||
name: "Linux Kernel"
|
|
||||||
path: linux
|
|
||||||
url: rsync://rsync.kernel.org/pub/
|
|
||||||
delay: 12
|
|
||||||
|
|
||||||
index:
|
|
||||||
- ARCHLINUX
|
|
||||||
- UBUNTU UBUNTU_CD
|
|
||||||
- DEBIAN DEBIAN_CD
|
|
||||||
- FEDORA
|
|
||||||
- MANJARO
|
|
||||||
- RASPBIAN
|
|
||||||
- DIVIDER
|
|
||||||
- ARCHLINUXARM
|
|
||||||
- ASAHILINUX
|
|
||||||
- GNU
|
|
||||||
- LINUX
|
|
||||||
- UBUNTU_CD_OLD
|
|
|
@ -1,12 +1,50 @@
|
||||||
MIRRORNAME="${DEB_HOST}"
|
########################################################################
|
||||||
TO="${DEB_PATH}"
|
########################################################################
|
||||||
|
## This is a sample configuration file for the ftpsync mirror script. ##
|
||||||
|
## Only options most users may need are included. For documentation ##
|
||||||
|
## and all available options see ftpsync.conf(5). ##
|
||||||
|
########################################################################
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
echo ${BASE_DIR}
|
||||||
|
echo ${DATA_DIR}
|
||||||
|
|
||||||
|
MIRRORNAME="mirror.morgan.kr"
|
||||||
|
TO="${DATA_DIR}/debian"
|
||||||
|
# MAILTO="$LOGNAME"
|
||||||
HUB=false
|
HUB=false
|
||||||
RSYNC_HOST="${DEB_UPSTREAM}"
|
|
||||||
|
########################################################################
|
||||||
|
## Connection options
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
RSYNC_HOST="mirrors.xtom.jp"
|
||||||
RSYNC_PATH="debian"
|
RSYNC_PATH="debian"
|
||||||
INFO_MAINTAINER="${DEB_ADMIN}"
|
# RSYNC_USER=
|
||||||
INFO_COUNTRY="${DEB_COUNTRY}"
|
# RSYNC_PASSWORD=
|
||||||
INFO_LOCATION="${DEB_LOCATION}"
|
|
||||||
INFO_THROUGHPUT=1Gbps
|
########################################################################
|
||||||
LOGDIR="${DEB_LOG}"
|
## Mirror information options
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
INFO_MAINTAINER="Morgan <mirror@morgan.kr>"
|
||||||
|
# INFO_SPONSOR="Example <https://example.com>"
|
||||||
|
INFO_COUNTRY=KR
|
||||||
|
INFO_LOCATION="Seoul, Korea"
|
||||||
|
INFO_THROUGHPUT=1Gb
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
## Include and exclude options
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
# ARCH_INCLUDE=
|
||||||
|
# ARCH_EXCLUDE=
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
## Log option
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
LOGDIR="${BASE_DIR}/logs"
|
||||||
|
|
||||||
UIPRETRIES=9
|
UIPRETRIES=9
|
||||||
TRACEHOST="${DEB_HOST}"
|
TRACEHOST="mirror.morgan.kr"
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
import requests, json, sys
|
|
||||||
from bs4 import BeautifulSoup as bs4
|
|
||||||
|
|
||||||
def tree(idx: int, flag = False) -> str:
|
|
||||||
idx += 1
|
|
||||||
if idx == 1:
|
|
||||||
if flag :
|
|
||||||
return "├────"
|
|
||||||
return "├──"
|
|
||||||
elif idx == 2:
|
|
||||||
if flag :
|
|
||||||
return "│ ├────"
|
|
||||||
return "│ ├──"
|
|
||||||
else:
|
|
||||||
if flag :
|
|
||||||
return "│ " * (idx - 2) + "├────"
|
|
||||||
return "│ " * (idx - 2) + "├──"
|
|
||||||
|
|
||||||
def parseIndex(url, base = "", idx = 0, dirs = [], ret = []):
|
|
||||||
|
|
||||||
print(f"D {(tree(idx)+url):<40} {''.join(dirs):>80}")
|
|
||||||
html = bs4(requests.get(base + url).text, features="html.parser")
|
|
||||||
|
|
||||||
hrefs = [a["href"] for a in html.find_all('a')]
|
|
||||||
hrefs = [i for i in hrefs if i[0] != '?']
|
|
||||||
fls = []
|
|
||||||
for href in hrefs:
|
|
||||||
if href[-1] == "/": # if dir
|
|
||||||
if href[0] != "/" and href[0] != ".":
|
|
||||||
parseIndex(href, base + url, idx + 1, dirs + [href], ret)
|
|
||||||
else:
|
|
||||||
if href[0:2] == "./" and "/" not in href[2:]:
|
|
||||||
href = href[2:]
|
|
||||||
assert "/" not in href
|
|
||||||
print(f"F {(tree(idx, 1)+href):<80}") # if file
|
|
||||||
fls.append(href)
|
|
||||||
|
|
||||||
while len(ret) <= idx:
|
|
||||||
ret.append({})
|
|
||||||
|
|
||||||
if ''.join(dirs) not in ret[idx].keys():
|
|
||||||
ret[idx][''.join(dirs)] = []
|
|
||||||
|
|
||||||
for fl in fls:
|
|
||||||
ret[idx][''.join(dirs)].append({fl: base + url + fl})
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
|
||||||
if len(sys.argv) != 3 and len(sys.argv) != 4:
|
|
||||||
print("Usage: createFetch.py [URL] [Path] (fetch)")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
if "http" in sys.argv[1]:
|
|
||||||
if input(f"[*] Download from {sys.argv[1]}? ") in "Yy":
|
|
||||||
url = sys.argv[1]
|
|
||||||
else:
|
|
||||||
sys.exit()
|
|
||||||
else:
|
|
||||||
print("[*] Not supported")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
bpath = sys.argv[2]
|
|
||||||
assert(bpath[-1] == '/')
|
|
||||||
|
|
||||||
print()
|
|
||||||
print(f"[*] Downloading File list from {url} with base path {bpath}")
|
|
||||||
|
|
||||||
files = parseIndex('', base = url, dirs = [bpath])
|
|
||||||
filename = url.split('/')[2]+'.fetch'
|
|
||||||
|
|
||||||
if len(sys.argv) == 4:
|
|
||||||
filename = sys.argv[3]
|
|
||||||
|
|
||||||
with open(filename, 'w') as f:
|
|
||||||
f.write(json.dumps(files, indent=4))
|
|
||||||
|
|
||||||
print()
|
|
||||||
print(f"[*] Saved to {filename}.")
|
|
|
@ -1,114 +0,0 @@
|
||||||
# import asyncio, aiohttp, aiofiles
|
|
||||||
import json, os, sys
|
|
||||||
import requests, time
|
|
||||||
# from tqdm import tqdm
|
|
||||||
|
|
||||||
def byteSize(size):
|
|
||||||
pr = ""
|
|
||||||
if size > 1024:
|
|
||||||
size = round(size / 1024, 1)
|
|
||||||
pr = "K"
|
|
||||||
if size > 1024:
|
|
||||||
size = round(size / 1024, 1)
|
|
||||||
pr = "M"
|
|
||||||
if size > 1024:
|
|
||||||
size = round(size / 1024, 1)
|
|
||||||
pr = "G"
|
|
||||||
return f"{size}{pr}"
|
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
|
||||||
print("Usage: getFiles.py [fetch file]")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
listf = sys.argv[1]
|
|
||||||
if not os.path.exists(listf):
|
|
||||||
print("There is no such file..")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
print(f"Downloading from fetchFile {listf}")
|
|
||||||
|
|
||||||
def spchr(string, num = 25, pad = 0):
|
|
||||||
if len(string) > num:
|
|
||||||
string = string[0:20] + ".." + string[-4:]
|
|
||||||
if pad > num:
|
|
||||||
string = string + ' '*(pad-len(string))
|
|
||||||
return string
|
|
||||||
|
|
||||||
with open(listf, 'r') as f:
|
|
||||||
jstr = json.loads(f.read())
|
|
||||||
|
|
||||||
for stage in jstr:
|
|
||||||
for redirs in stage.keys():
|
|
||||||
der = redirs.split('/')
|
|
||||||
for i in range(len(der)):
|
|
||||||
dpath = '/'.join(der[0:i])
|
|
||||||
if not os.path.exists(dpath) and dpath:
|
|
||||||
print(f"[*] Making new directory {dpath}")
|
|
||||||
os.mkdir(dpath)
|
|
||||||
|
|
||||||
for stage in jstr:
|
|
||||||
for dosta in stage:
|
|
||||||
print(f"[*] Downloading path {dosta}")
|
|
||||||
fpaths = []
|
|
||||||
furls = []
|
|
||||||
|
|
||||||
for fls in stage[dosta]:
|
|
||||||
fna = list(fls.keys())[0]
|
|
||||||
fpa = fls[fna]
|
|
||||||
fpaths.append(dosta + fna)
|
|
||||||
furls.append(fpa)
|
|
||||||
|
|
||||||
assert len(fpaths) == len(furls)
|
|
||||||
|
|
||||||
# pbar = tqdm(total=len(fpaths))
|
|
||||||
# print(furls)
|
|
||||||
dlist = []
|
|
||||||
for url, path in zip(furls, fpaths):
|
|
||||||
if os.path.exists(path):
|
|
||||||
flen = os.path.getsize(path)
|
|
||||||
wlen = requests.get(url, stream=True).headers['Content-length']
|
|
||||||
if int(flen) != int(wlen):
|
|
||||||
dlist.append((path, url))
|
|
||||||
else:
|
|
||||||
dlist.append((path, url))
|
|
||||||
|
|
||||||
for path, url in dlist:
|
|
||||||
print(f"[*] Fetch {url} ", end = "")
|
|
||||||
wfil = requests.get(url, stream=True)
|
|
||||||
wlen = wfil.headers['Content-length']
|
|
||||||
print(byteSize(int(wlen)))
|
|
||||||
|
|
||||||
with open(path, 'wb') as f:
|
|
||||||
if wlen is None: # no content length header
|
|
||||||
f.write(wfil.content)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# pbar = tqdm(total=int(wlen), desc=spchr(' '+path, pad = 30))
|
|
||||||
for data in wfil.iter_content(chunk_size=4096):
|
|
||||||
f.write(data)
|
|
||||||
# print(".", end = "")
|
|
||||||
# pbar.update(len(data))
|
|
||||||
# print()
|
|
||||||
# async def getHTTP(session, url):
|
|
||||||
# async with session.get(url) as resp:
|
|
||||||
# try:
|
|
||||||
# reqa = await resp.read()
|
|
||||||
# # pbar.update(1)
|
|
||||||
# return reqa
|
|
||||||
# except:
|
|
||||||
# print(url)
|
|
||||||
# return
|
|
||||||
|
|
||||||
# async def agetReq():
|
|
||||||
# async with aiohttp.ClientSession() as session:
|
|
||||||
# tasks = []
|
|
||||||
# for url in furls:
|
|
||||||
# tasks.append(asyncio.ensure_future(getHTTP(session, url)))
|
|
||||||
|
|
||||||
# getReqs = await asyncio.gather(*tasks)
|
|
||||||
|
|
||||||
# for i, getReq in enumerate(getReqs):
|
|
||||||
# async with aiofiles.open(fpaths[i], mode='wb') as handle:
|
|
||||||
# await handle.write(getReq)
|
|
||||||
|
|
||||||
# asyncio.run(agetReq())
|
|
119
scripts/index.py
119
scripts/index.py
|
@ -1,86 +1,67 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python
|
||||||
|
|
||||||
import os, sys
|
import os, sys, re
|
||||||
import yaml
|
|
||||||
import jinja2
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
# def get_last_sync(repo_name):
|
base_path = sys.argv[1]
|
||||||
# if os.path.exists(SYNC_LOG):
|
out_path = sys.argv[2]
|
||||||
# with open(SYNC_LOG, 'r') as log_file:
|
assert os.path.exists(base_path)
|
||||||
# log_all = reversed(log_file.readlines())
|
|
||||||
# for logline in log_all:
|
|
||||||
# dist, time, stat = logline.split()
|
|
||||||
# if repo_name == dist and stat =="SUCCESS":
|
|
||||||
# return datetime.datetime.strptime(time, '%Y-%m-%dT%H:%MZ').strftime("%Y-%m-%d %H:%M")
|
|
||||||
# return "Not Synced"
|
|
||||||
|
|
||||||
# main()
|
log_path = os.path.join(base_path, "logs/all.log")
|
||||||
|
assert os.path.exists(log_path)
|
||||||
|
|
||||||
if __name__=="__main__":
|
html_path = os.path.join(base_path, "scripts/base.html")
|
||||||
|
index = os.path.join(out_path, "index.html")
|
||||||
|
assert os.path.exists(html_path)
|
||||||
|
|
||||||
if len(sys,argv) == 3:
|
with open(log_path, 'r') as f:
|
||||||
print(sys.argv)
|
log_file = f.read().splitlines()
|
||||||
|
log_file.reverse()
|
||||||
|
|
||||||
CONFIG_PATH = sys.argv[1]
|
with open(html_path, 'r') as f:
|
||||||
|
html_file = f.read()
|
||||||
|
dists = re.findall("@@([^@@]+)@@", html_file)
|
||||||
|
|
||||||
with open(CONFIG_PATH, 'r') as f:
|
print(dists)
|
||||||
config = yaml.safe_load(f)
|
|
||||||
|
|
||||||
|
logs = {}
|
||||||
|
for dist in dists:
|
||||||
|
logs[dist] = []
|
||||||
|
|
||||||
BASE_DIR = config.get("BASE_DIR", ".")
|
for dist in logs:
|
||||||
THEME = "new"
|
for logline in log_file:
|
||||||
TEMPLATES_DIR = os.path.join(os.path.join(BASE_DIR, "scripts/templates"), THEME)
|
time, stat, disk = logline.split(" ")
|
||||||
LOG_DIR = os.path.join(BASE_DIR, config['global'].get("log_dir", "logs"))
|
if stat == "DONE" and dist == disk:
|
||||||
OUTPUT_PATH = os.path.join(os.path.join(BASE_DIR, config['global'].get("data_dir", ".")), "index.html")
|
logs[dist] = datetime.datetime.strptime(time, '%Y%m%d_%H%M').strftime("%Y-%m-%d %H:%M")
|
||||||
|
break
|
||||||
|
logs[dist] = "Not Synced"
|
||||||
|
|
||||||
env = jinja2.Environment(loader=jinja2.FileSystemLoader(TEMPLATES_DIR))
|
stats = {}
|
||||||
base_template = env.get_template('base.html')
|
for dist in dists:
|
||||||
full_template = env.get_template('full.html')
|
for logline in log_file:
|
||||||
half_template = env.get_template('half.html')
|
time, stat, disk = logline.split(" ")
|
||||||
|
if dist == disk:
|
||||||
|
stats[dist] = stat, datetime.datetime.strptime(time, '%Y%m%d_%H%M').strftime("%Y-%m-%d %H:%M")
|
||||||
|
break
|
||||||
|
stats[dist] = (-1, "Not Synced")
|
||||||
|
|
||||||
main_repos = []
|
print(logs)
|
||||||
additional_repos = []
|
print(stats)
|
||||||
|
|
||||||
DIV = 0
|
for dist in dists:
|
||||||
for line in config['index']:
|
stat, tt = stats[dist]
|
||||||
if line == "DIVIDER":
|
if stat == "ERROR":
|
||||||
DIV = 1
|
stat = f" (Error @ {tt})"
|
||||||
continue
|
elif stat == "STARTED":
|
||||||
repos_line = line.split()
|
stat = f" (Running @ {tt})"
|
||||||
for repo_name in repos_line:
|
|
||||||
repo_data = config['repos'].get(repo_name)
|
|
||||||
if not repo_data:
|
|
||||||
continue
|
|
||||||
|
|
||||||
context = {
|
|
||||||
'path': repo_data['path'],
|
|
||||||
'name': repo_data['name'],
|
|
||||||
# 'lastsync': get_last_sync(repo_name),
|
|
||||||
'lastsync': repo_data.get('lastsync', "Not Synced"),
|
|
||||||
'upstream': repo_data['url']
|
|
||||||
}
|
|
||||||
print(context)
|
|
||||||
if len(repos_line) > 1:
|
|
||||||
(main_repos if not DIV else additional_repos).append(half_template.render(**context))
|
|
||||||
else:
|
else:
|
||||||
(main_repos if not DIV else additional_repos).append(full_template.render(**context))
|
stat = ""
|
||||||
|
|
||||||
html_output = base_template.render(
|
if stat:
|
||||||
repos="\n".join(main_repos),
|
stat = f"</p><p class=\"text-gray-500 dark:text-gray-400\">{stat}</p>"
|
||||||
repos_more="\n".join(additional_repos)
|
html_file = html_file.replace(f"@@{dist}@@", f"{logs[dist]}{stat}")
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
with open(index, 'w') as f:
|
||||||
with open(OUTPUT_PATH, 'w') as f:
|
f.write(html_file)
|
||||||
f.write(html_output)
|
|
||||||
|
|
||||||
except:
|
print("Written to index.html")
|
||||||
if len(sys.argv) == 2:
|
|
||||||
if os.path.exists(sys.argv[1]):
|
|
||||||
if not os.path.isdir(sys.argv[1]):
|
|
||||||
print(f"Writing to {sys.argv[1]}")
|
|
||||||
with open(sys.argv[1], 'w') as f:
|
|
||||||
f.write(html_output)
|
|
||||||
else:
|
|
||||||
print(html_output)
|
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
user user;
|
|
||||||
worker_processes auto;
|
|
||||||
pid /run/nginx.pid;
|
|
||||||
include /etc/nginx/modules-enabled/*.conf;
|
|
||||||
|
|
||||||
events {
|
|
||||||
worker_connections 768;
|
|
||||||
# multi_accept on;
|
|
||||||
}
|
|
||||||
|
|
||||||
http {
|
|
||||||
|
|
||||||
##
|
|
||||||
# Basic Settings
|
|
||||||
##
|
|
||||||
|
|
||||||
sendfile on;
|
|
||||||
tcp_nopush on;
|
|
||||||
types_hash_max_size 2048;
|
|
||||||
# server_tokens off;
|
|
||||||
|
|
||||||
# server_names_hash_bucket_size 64;
|
|
||||||
# server_name_in_redirect off;
|
|
||||||
|
|
||||||
include /etc/nginx/mime.types;
|
|
||||||
default_type application/octet-stream;
|
|
||||||
|
|
||||||
##
|
|
||||||
# SSL Settings
|
|
||||||
##
|
|
||||||
|
|
||||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
|
|
||||||
ssl_prefer_server_ciphers on;
|
|
||||||
|
|
||||||
##
|
|
||||||
# Logging Settings
|
|
||||||
##
|
|
||||||
|
|
||||||
log_format main_ext '$remote_addr - $remote_user [$time_local] "$request" '
|
|
||||||
'$status $body_bytes_sent "$http_referer" '
|
|
||||||
'"$http_user_agent" "$http_x_forwarded_for" '
|
|
||||||
'"$host" sn="$server_name" ' 'rt=$request_time '
|
|
||||||
'ua="$upstream_addr" us="$upstream_status" '
|
|
||||||
'ut="$upstream_response_time" ul="$upstream_response_length" '
|
|
||||||
'cs=$upstream_cache_status' ;
|
|
||||||
|
|
||||||
access_log /var/log/nginx/access.log;
|
|
||||||
error_log /var/log/nginx/error.log;
|
|
||||||
|
|
||||||
##
|
|
||||||
# Gzip Settings
|
|
||||||
##
|
|
||||||
|
|
||||||
gzip on;
|
|
||||||
|
|
||||||
# gzip_vary on;
|
|
||||||
# gzip_proxied any;
|
|
||||||
# gzip_comp_level 6;
|
|
||||||
# gzip_buffers 16 8k;
|
|
||||||
# gzip_http_version 1.1;
|
|
||||||
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
|
||||||
|
|
||||||
##
|
|
||||||
# Virtual Host Configs
|
|
||||||
##
|
|
||||||
|
|
||||||
include /etc/nginx/conf.d/*.conf;
|
|
||||||
include /etc/nginx/sites-enabled/*;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#mail {
|
|
||||||
# # See sample authentication script at:
|
|
||||||
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
|
|
||||||
#
|
|
||||||
# # auth_http localhost/auth.php;
|
|
||||||
# # pop3_capabilities "TOP" "USER";
|
|
||||||
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
|
|
||||||
#
|
|
||||||
# server {
|
|
||||||
# listen localhost:110;
|
|
||||||
# protocol pop3;
|
|
||||||
# proxy on;
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# server {
|
|
||||||
# listen localhost:143;
|
|
||||||
# protocol imap;
|
|
||||||
# proxy on;
|
|
||||||
# }
|
|
||||||
#}
|
|
|
@ -1,21 +0,0 @@
|
||||||
server {
|
|
||||||
listen 80 ;
|
|
||||||
listen [::]:80 ;
|
|
||||||
server_name repo.city;
|
|
||||||
|
|
||||||
access_log /var/log/nginx/repo-city-access.log main_ext;
|
|
||||||
error_log /var/log/nginx/repo-city-error.log warn;
|
|
||||||
|
|
||||||
root /srv/mirror;
|
|
||||||
|
|
||||||
location /scripts/ {
|
|
||||||
return 404;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
autoindex on;
|
|
||||||
fancyindex on;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
server {
|
|
||||||
listen 127.0.0.1:80;
|
|
||||||
server_name 127.0.0.1;
|
|
||||||
location /nginx_status {
|
|
||||||
stub_status on;
|
|
||||||
access_log off;
|
|
||||||
allow 127.0.0.1;
|
|
||||||
deny all;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,230 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import re, math, os, sys, datetime
|
||||||
|
|
||||||
|
path_list = ["archlinux", "/archlinuxarm", "/asahilinux",
|
||||||
|
"/cd-image", "/debian", "/debian-cd", "/fedora",
|
||||||
|
"/gnu", "/index.html", "/kali", "/kali-images",
|
||||||
|
"/linux", "/manjaro", "/raspbian", "/static",
|
||||||
|
"/ubuntu", "/ubuntu-cd", "/ubuntu-old", "/"]
|
||||||
|
|
||||||
|
def byte_human(size_bytes):
|
||||||
|
if size_bytes == 0:
|
||||||
|
return "0B"
|
||||||
|
size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
|
||||||
|
i = int(math.floor(math.log(size_bytes, 1024)))
|
||||||
|
p = math.pow(1024, i)
|
||||||
|
s = round(size_bytes / p, 2)
|
||||||
|
return "%s%s" % (s, size_name[i])
|
||||||
|
|
||||||
|
|
||||||
|
def parse_req_line(http_entry):
|
||||||
|
req = {}
|
||||||
|
http_parsed = http_entry.split()
|
||||||
|
if http_parsed:
|
||||||
|
if http_parsed[0] in ["HEAD", "POST", "GET", "OPTION"]:
|
||||||
|
req["method"] = http_parsed[0]
|
||||||
|
if http_parsed[1][0] == "/":
|
||||||
|
req["path"] = http_parsed[1]
|
||||||
|
return req
|
||||||
|
|
||||||
|
|
||||||
|
def get_path_parent(path):
|
||||||
|
path = path.split("?")[0].split("&")[0].split("/")
|
||||||
|
if len(path) == 1:
|
||||||
|
return "/" + path[0]
|
||||||
|
else:
|
||||||
|
return "/".join(path[:2])
|
||||||
|
|
||||||
|
def get_date_range(all_log):
|
||||||
|
dates = sorted([ i[2] for i in all_log ])
|
||||||
|
dates = [datetime.datetime.strptime(i, "%d/%b/%Y:%H:%M:%S %z").strftime("%m/%d %H:%M:%S") for i in dates]
|
||||||
|
print(f"Date: {dates[0]} ~ {dates[-1]}")
|
||||||
|
|
||||||
|
|
||||||
|
def parse_log_entry(entry):
|
||||||
|
pattern = r'([\d\.]+) - (\S+) \[(.*?)\] "(.*?)" (\d+) (\d+) "(.*?)" "(.*?)" "(.*?)" "(.*?)" sn="(.*?)" rt=([\d\.]+) [^\n]+'
|
||||||
|
|
||||||
|
match = re.match(pattern, entry)
|
||||||
|
|
||||||
|
if not match:
|
||||||
|
return None
|
||||||
|
|
||||||
|
lm = list(match.groups())
|
||||||
|
assert len(lm) == 12
|
||||||
|
|
||||||
|
if "HTTP" not in lm[3]:
|
||||||
|
return
|
||||||
|
|
||||||
|
log_entry = {}
|
||||||
|
log_entry["client"] = lm[0]
|
||||||
|
log_entry["user"] = lm[1]
|
||||||
|
log_entry["time"] = datetime.datetime.strptime(lm[2], "%d/%b/%Y:%H:%M:%S %z")
|
||||||
|
log_entry["req"] = lm[3]
|
||||||
|
log_entry["status"] = lm[4]
|
||||||
|
log_entry["bytes"] = lm[5]
|
||||||
|
log_entry["referer"] = lm[6]
|
||||||
|
log_entry["ua"] = lm[7]
|
||||||
|
log_entry["forward"] = lm[8]
|
||||||
|
log_entry["host"] = lm[9]
|
||||||
|
log_entry["server"] = lm[10]
|
||||||
|
log_entry["reqtime"] = lm[11]
|
||||||
|
|
||||||
|
return log_entry
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_log_entry(log_file):
|
||||||
|
with open(log_file, "r") as f:
|
||||||
|
full_log = f.read().split("\n")
|
||||||
|
log_entries = [ i for i in [ parse_log_entry(log) for log in full_log[:-1] ] if i ]
|
||||||
|
return log_entries
|
||||||
|
|
||||||
|
|
||||||
|
def main(log_file, logs=[]):
|
||||||
|
all_logs = get_all_log_entry(log_file) if not logs else logs
|
||||||
|
|
||||||
|
log_by_date = {}
|
||||||
|
for entry in all_logs:
|
||||||
|
date_day = datetime.datetime.strftime(entry.get("time"), "%Y-%m-%d")
|
||||||
|
if date_day not in log_by_date:
|
||||||
|
log_by_date[date_day] = []
|
||||||
|
log_by_date[date_day].append(entry)
|
||||||
|
|
||||||
|
for day in log_by_date:
|
||||||
|
paths = {}
|
||||||
|
for entry in log_by_date[day]:
|
||||||
|
req = parse_req_line(entry.get("req"))
|
||||||
|
|
||||||
|
if path := req.get("path"):
|
||||||
|
path_parent = get_path_parent(path)
|
||||||
|
|
||||||
|
if path_parent not in path_list:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if path_parent not in paths:
|
||||||
|
paths[path_parent] = [0, 0]
|
||||||
|
|
||||||
|
paths[path_parent][0] += int(entry.get("bytes"))
|
||||||
|
paths[path_parent][1] += 1
|
||||||
|
|
||||||
|
print(day)
|
||||||
|
print('-'*36)
|
||||||
|
print(f'{"Path":<14} {"Count":<10} Transfer')
|
||||||
|
print('-'*36)
|
||||||
|
for path in sorted(paths):
|
||||||
|
print(f"{path:<14} {paths[path][1]:<10} {byte_human(paths[path][0])}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def main_geo(log_file, logs = []):
|
||||||
|
import geoip2.database
|
||||||
|
reader = geoip2.database.Reader('GeoLite2-Country.mmdb')
|
||||||
|
|
||||||
|
all_logs = get_all_log_entry(log_file) if not logs else logs
|
||||||
|
c = len(all_logs)
|
||||||
|
# print(c)
|
||||||
|
geolocstat = {}
|
||||||
|
for n, log in enumerate(all_logs):
|
||||||
|
req = parse_req_line(log.get("req"))
|
||||||
|
if path := req.get("path"):
|
||||||
|
path_parent = get_path_parent(path)
|
||||||
|
|
||||||
|
try:
|
||||||
|
geoloc = reader.country(log['client']).country.iso_code
|
||||||
|
except:
|
||||||
|
geoloc = "XX"
|
||||||
|
|
||||||
|
print(f"[{int(100*n/c):>3}%] {geoloc} {log['client']:>15} {byte_human(int(log['bytes'])):>8} {path_parent}", file=sys.stderr)
|
||||||
|
if geoloc not in geolocstat:
|
||||||
|
geolocstat[geoloc] = 0
|
||||||
|
geolocstat[geoloc] += int(log['bytes'])
|
||||||
|
print(file=sys.stderr)
|
||||||
|
|
||||||
|
sortdict = lambda x : {k: v for k, v in sorted(x.items(), key=lambda item: item[1], reverse=True)}
|
||||||
|
for geo in sortdict(geolocstat):
|
||||||
|
print(geo, byte_human(geolocstat[geo]))
|
||||||
|
|
||||||
|
def main_date(log_file, logs=[]):
|
||||||
|
all_logs = get_all_log_entry(log_file) if not logs else logs
|
||||||
|
date_sorted = (sorted(all_logs, key=(lambda x: x['time'])))
|
||||||
|
st = datetime.datetime.strftime(date_sorted[0]['time'], "%Y-%m-%d %H:%M:%S")
|
||||||
|
ed = datetime.datetime.strftime(date_sorted[-1]['time'], "%Y-%m-%d %H:%M:%S")
|
||||||
|
total_bytes = sum([int(x['bytes']) for x in all_logs])
|
||||||
|
print(f"------- Log {log_file} -------\n Date: {st} ~ {ed}\n Entry count: {len(all_logs)}\n Total bytes: {byte_human(total_bytes)}")
|
||||||
|
|
||||||
|
def main_html(log_file):
|
||||||
|
all_logs = get_all_log_entry(log_file)
|
||||||
|
###
|
||||||
|
date_sorted = (sorted(all_logs, key=(lambda x: x['time'])))
|
||||||
|
st = datetime.datetime.strftime(date_sorted[0]['time'], "%Y-%m-%d %H:%M:%S")
|
||||||
|
ed = datetime.datetime.strftime(date_sorted[-1]['time'], "%Y-%m-%d %H:%M:%S")
|
||||||
|
total_bytes = sum([int(x['bytes']) for x in all_logs])
|
||||||
|
print(f"-------- Log Info --------\nDate: {st} ~ {ed}\nEntry count: {len(all_logs)}\nTotal bytes: {byte_human(total_bytes)}\n")
|
||||||
|
###
|
||||||
|
print("-------- By Path ---------")
|
||||||
|
|
||||||
|
paths = {}
|
||||||
|
for entry in all_logs:
|
||||||
|
req = parse_req_line(entry.get("req"))
|
||||||
|
|
||||||
|
if path := req.get("path"):
|
||||||
|
path_parent = get_path_parent(path)
|
||||||
|
|
||||||
|
if path_parent not in path_list:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if path_parent not in paths:
|
||||||
|
paths[path_parent] = [0, 0]
|
||||||
|
|
||||||
|
paths[path_parent][0] += int(entry.get("bytes"))
|
||||||
|
paths[path_parent][1] += 1
|
||||||
|
|
||||||
|
for path in sorted(paths):
|
||||||
|
print(f"{path:<14} {paths[path][1]:<10} {byte_human(paths[path][0])}")
|
||||||
|
print()
|
||||||
|
###
|
||||||
|
print("------- By Country -------")
|
||||||
|
import geoip2.database
|
||||||
|
reader = geoip2.database.Reader('/srv/mirror/scripts/GeoLite2-Country.mmdb')
|
||||||
|
|
||||||
|
geolocstat = {}
|
||||||
|
for n, log in enumerate(all_logs):
|
||||||
|
req = parse_req_line(log.get("req"))
|
||||||
|
if path := req.get("path"):
|
||||||
|
path_parent = get_path_parent(path)
|
||||||
|
try:
|
||||||
|
geoloc = reader.country(log['client']).country.iso_code
|
||||||
|
except:
|
||||||
|
geoloc = "XX"
|
||||||
|
if geoloc not in geolocstat:
|
||||||
|
geolocstat[geoloc] = 0
|
||||||
|
geolocstat[geoloc] += int(log['bytes'])
|
||||||
|
|
||||||
|
geos = []
|
||||||
|
sortdict = lambda x : {k: v for k, v in sorted(x.items(), key=lambda item: item[1], reverse=True)}
|
||||||
|
for geo in sortdict(geolocstat):
|
||||||
|
if geo:
|
||||||
|
geos.append(f"{geo} {byte_human(geolocstat[geo])}")
|
||||||
|
print('\n'.join(geos[:min(len(geos),7)]))
|
||||||
|
print("--------------------------")
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print("Error: ngparse {stat,parse,geo} [ log file ]\n* log file must have extended format.")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
if os.path.exists(sys.argv[2]):
|
||||||
|
logfile = sys.argv[2]
|
||||||
|
else:
|
||||||
|
print("Error: File doesnt exists.")
|
||||||
|
exit
|
||||||
|
|
||||||
|
if sys.argv[1] == "stat":
|
||||||
|
main(logfile)
|
||||||
|
elif sys.argv[1] == "geo":
|
||||||
|
main_geo(logfile)
|
||||||
|
elif sys.argv[1] == "date":
|
||||||
|
main_date(logfile)
|
||||||
|
elif sys.argv[1] == "html":
|
||||||
|
main_html(logfile)
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
echo "<h3><bold>$(date +%Y%m%d)</bold></h3><h4><bold>Log</bold></h4>"> /srv/mirror/pub/stat/stat.html
|
||||||
|
echo "<pre>$(/srv/mirror/scripts/ngparse html /var/log/nginx/mirror/access.log)</pre>" >> /srv/mirror/pub/stat/stat.html
|
||||||
|
echo "<h4><bold>Traffic</bold></h4>" >> /srv/mirror/pub/stat/stat.html
|
||||||
|
echo "<pre>$(vnstat -i enp1s0 --days 10 | sed 's/ //' | tail -n +4)</pre>" >> /srv/mirror/pub/stat/stat.html
|
||||||
|
|
||||||
|
for i in /var/log/nginx/mirror/access.log-*;
|
||||||
|
do
|
||||||
|
DATE=${i#*-}
|
||||||
|
echo $DATE
|
||||||
|
if [ ! -f /srv/mirror/pub/stat/$DATE.html ];
|
||||||
|
then
|
||||||
|
echo $DATE.html;
|
||||||
|
echo "<date>$DATE</date>" > /srv/mirror/pub/stat/$DATE.html;
|
||||||
|
echo "<pre>$(/srv/mirror/scripts/ngparse html $i)</pre>" >> /srv/mirror/pub/stat/$DATE.html
|
||||||
|
echo "<br/><br/>" >> /srv/mirror/pub/stat/$DATE.html
|
||||||
|
fi
|
||||||
|
done
|
371
scripts/sync.sh
371
scripts/sync.sh
|
@ -1,301 +1,110 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Default locations.
|
TIMENOW=$(date '+%Y%m%d_%H%M')
|
||||||
CONFIG="./scripts/config.yml"
|
BASE_DIR="/srv/mirror"
|
||||||
YAML="./scripts/yq"
|
ALERT="$BASE_DIR/scripts/alert.sh"
|
||||||
|
DATA_DIR="$BASE_DIR/pub"
|
||||||
|
|
||||||
function usage() {
|
echo $TIMENOW $BASE_DIR $DATA_DIR $USER
|
||||||
cat <<EOF
|
|
||||||
Usage: $0 [-c config_path] [-y yq_path]
|
|
||||||
|
|
||||||
Flags:
|
if [[ "$USER" == "root" ]]; then
|
||||||
-c, --config_path: config file path
|
echo "Dont run as root."
|
||||||
-y, --yq: yq binary path (>v4.35.2)
|
su user $0 $@
|
||||||
-v, --verbose
|
|
||||||
-> -b, --base-dir: overrides base_dir
|
|
||||||
-> -d, --dry-run: dry run
|
|
||||||
EOF
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
function error() {
|
|
||||||
echo $0: "$1"
|
|
||||||
exit
|
exit
|
||||||
}
|
|
||||||
|
|
||||||
function debug() {
|
|
||||||
if [[ -v DEBUG ]]; then
|
|
||||||
echo debug: "$1"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function execute() {
|
|
||||||
debug "Executing script: \"$@\""
|
|
||||||
if [[ ! -v DRY_RUN ]]; then
|
|
||||||
$@
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_yaml() {
|
|
||||||
echo $($YAML eval ".$1" "${CONFIG}")
|
|
||||||
}
|
|
||||||
|
|
||||||
get_repo_config() {
|
|
||||||
local LOCAL_CFG=$($YAML eval ".repos.$1.$2" "${CONFIG}")
|
|
||||||
if [[ "$LOCAL_CFG" == "null" || "$LOCAL_CFG" == "" ]]; then
|
|
||||||
echo $($YAML eval ".defaults.$2" "${CONFIG}");
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
echo $LOCAL_CFG
|
|
||||||
return 0
|
|
||||||
|
|
||||||
# 1 if global 0 if local
|
|
||||||
}
|
|
||||||
|
|
||||||
sync_repo() {
|
|
||||||
local repo=$1
|
|
||||||
local name=$(get_repo_config ${repo} name)
|
|
||||||
local type=$(get_repo_config ${repo} type)
|
|
||||||
local url=$(get_repo_config ${repo} url)
|
|
||||||
local path=$(get_repo_config ${repo} path)
|
|
||||||
local log; log=$(get_repo_config ${repo} log) || log=${log/\${path\}/$path};
|
|
||||||
|
|
||||||
if [[ "$type" == "null" || "$url" == "null" || "$path" == "null" || "$log" == "null" ]]; then
|
|
||||||
echo "Error config wrong."
|
|
||||||
return
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
full_path="${BASE_DIR}/$(parse_yaml global.data_dir)/$path/"
|
option="-rtlHpvi --chmod=D0755,F0644 --partial --hard-links --safe-links --stats --delete --delete-after --delay-updates --max-delete=70000"
|
||||||
log="${BASE_DIR}/$log"
|
exclude="--exclude=.*.?????? --exclude='.~tmp~/' --exclude='Packages*' --exclude='Sources*' --exclude='Release*' --exclude='*.links.tar.gz*' --exclude='/other' --exclude='/sources'"
|
||||||
|
|
||||||
echo -e "--------\nRepo: $name\nType: $type\nUpstream: $url\nPath: $full_path\nLog: $log\n--------"
|
ubuntu="rsync://rsync.archive.ubuntu.com/ubuntu/"
|
||||||
|
ubuntu_cd="rsync://releases.ubuntu.com/releases/"
|
||||||
if [[ ! -v DRY_RUN ]]; then
|
ubuntu_cd_old="rsync://old-releases.ubuntu.com/releases/"
|
||||||
|
debian="rsync://mirrors.xtom.jp/debian/"
|
||||||
rotate_log $log
|
debian_cd="rsync://ftp.lanet.kr/debian-cd/"
|
||||||
|
fedora="rsync://dl.fedoraproject.org/fedora-enchilada/linux/"
|
||||||
case $type in
|
epel="rsync://dl.fedoraproject.org/fedora-epel/"
|
||||||
"rsync")
|
fedora_cd=""
|
||||||
local rsync_options=$(get_repo_config $repo 'rsync.options')
|
archlinux="rsync://mirrors.xtom.de/archlinux/"
|
||||||
local exclude_list=($(get_repo_config $repo 'rsync.exclude[]'))
|
raspbian="rsync://archive.raspbian.org/archive/"
|
||||||
local exclude=""
|
manjaro="rsync://ftp.riken.jp/manjaro/"
|
||||||
for ex in "${exclude_list[@]}"; do
|
gnu="rsync://ftp.gnu.org/gnu/"
|
||||||
exclude="${exclude} --exclude='${ex}'"
|
kali_images="rsync://repo.jing.rocks/kali-images"
|
||||||
done
|
kali="rsync://repo.jing.rocks/kali"
|
||||||
echo rsync ${rsync_options} ${exclude} $url $full_path >> $log
|
linux="rsync://rsync.kernel.org/pub/"
|
||||||
rsync ${rsync_options} ${exclude} $url $full_path >> $log 2>> ${log}-error
|
failtest="rsync://aa"
|
||||||
;;
|
if [[ ! -v $1 ]]; then
|
||||||
"ftpsync")
|
echo Not found.
|
||||||
cd ${BASE_DIR}/scripts
|
exit
|
||||||
|
|
||||||
export DEB_ADMIN="Morgan <mirror@devpg.net>"
|
|
||||||
export DEB_COUNTRY="Korea"
|
|
||||||
export DEB_LOCATION="Korea/Seoul"
|
|
||||||
export DEB_PATH="$full_path"
|
|
||||||
export DEB_HOST="$(parse_yaml global.hostname)"
|
|
||||||
export DEB_UPSTREAM="$url"
|
|
||||||
export DEB_LOG="${BASE_DIR}/$(parse_yaml global.log_dir)"
|
|
||||||
|
|
||||||
./ftpsync >> $log 2>> ${log}-error
|
|
||||||
cd ${BASE_DIR}
|
|
||||||
;;
|
|
||||||
"http")
|
|
||||||
echo ${repo} Fetch >> $log 2>> ${log}-error
|
|
||||||
python3 -u $BASE_DIR/scripts/getFetch.py "${url}" $full_path $BASE_DIR/scripts/${path}.fetch >> $log 2>> ${log}-error
|
|
||||||
echo ${repo} Download >> $log 2>> ${log}-error
|
|
||||||
python3 -u $BASE_DIR/scripts/getFile.py $BASE_DIR/scripts/${path}.fetch >> $log 2>> ${log}-error
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown type $type for $repo." | tee ${log}-error
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
clean_log $log
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
rotate_log() {
|
|
||||||
local log_file=$1
|
|
||||||
if [[ -f $log_file ]]; then
|
|
||||||
PREV_LOG=$(cat "$log_file" | head -n 1)
|
|
||||||
old_log_file="$(dirname $log_file)/old/$(basename $log_file)-$PREV_LOG"
|
|
||||||
mkdir -p "$(dirname $old_log_file)"
|
|
||||||
mv "$log_file" "$old_log_file"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local error_file=$1-error
|
ubuntu_cd_name="ubuntu-cd"
|
||||||
if [[ -f $error_file ]]; then
|
debian_cd_name="debian-cd"
|
||||||
PREV_LOG=$(cat "$error_file" | head -n 1)
|
ubuntu_cd_old_name="ubuntu-old"
|
||||||
old_error_file="$(dirname $error_file)/old/$(basename $error_file)-$PREV_LOG"
|
kali_images_name="kali-images"
|
||||||
mkdir -p "$(dirname $old_error_file)"
|
|
||||||
mv "$error_file" "$old_error_file"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo $TIMESTAMP >> $log_file
|
dist=$1
|
||||||
echo $TIMESTAMP >> $error_file
|
echo Syncing $1...
|
||||||
}
|
set -o pipefail
|
||||||
|
LASTLOG=`head -1 ${BASE_DIR}/logs/${dist}.log`
|
||||||
|
|
||||||
clean_log() {
|
mv ${BASE_DIR}/logs/${dist}.log ${BASE_DIR}/logs/previous/${dist}-${LASTLOG}.log
|
||||||
local error_file=$1-error
|
mv ${BASE_DIR}/logs/${dist}-error.log ${BASE_DIR}/logs/previous/${dist}-error-${LASTLOG}.log
|
||||||
nl=$(cat "$error_file" | wc -l)
|
|
||||||
if [ $nl -eq 1 ]; then
|
|
||||||
rm "$error_file"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function global_log() {
|
if [[ -v ${dist}_name ]]; then
|
||||||
GLOBAL_LOG_FILE="$(parse_yaml 'global.log')"
|
dist_name_var="${dist}_name"
|
||||||
echo "$1 $TIMESTAMP SUCCESS" >> $GLOBAL_LOG_FILE
|
dist_dir=${!dist_name_var}
|
||||||
}
|
|
||||||
|
|
||||||
function global_log_error() {
|
|
||||||
GLOBAL_LOG_FILE="$(parse_yaml 'global.log')"
|
|
||||||
echo "$1 $TIMESTAMP ERROR" >> $GLOBAL_LOG_FILE
|
|
||||||
}
|
|
||||||
|
|
||||||
##########
|
|
||||||
# Main #
|
|
||||||
##########
|
|
||||||
|
|
||||||
while [ "$1" != "" ]; do
|
|
||||||
case $1 in
|
|
||||||
-c | --config)
|
|
||||||
shift
|
|
||||||
if [[ -z $1 ]]; then
|
|
||||||
error "option '-c' requires argument 'config_path'"
|
|
||||||
fi
|
|
||||||
CONFIG=$1
|
|
||||||
;;
|
|
||||||
-y | --yq)
|
|
||||||
shift
|
|
||||||
if [[ -z $1 ]]; then
|
|
||||||
error "option '-y' requires argument 'yq_path'"
|
|
||||||
fi
|
|
||||||
YAML=$1
|
|
||||||
;;
|
|
||||||
-b | --base-dir)
|
|
||||||
shift
|
|
||||||
if [[ -z $1 ]]; then
|
|
||||||
error "option '-b' requires argument 'base_dir'"
|
|
||||||
fi
|
|
||||||
BASE_DIR_OVERRIDE=$1
|
|
||||||
;;
|
|
||||||
-h | --help)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
-v | --verbose)
|
|
||||||
DEBUG=1
|
|
||||||
;;
|
|
||||||
-d | --dry-run)
|
|
||||||
DRY_RUN=1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ -v DEBUG ]]; then
|
|
||||||
debug "DEBUG=1"
|
|
||||||
fi
|
|
||||||
if [[ -v DRY_RUN ]]; then
|
|
||||||
debug "DRY_RUN=1"
|
|
||||||
fi
|
|
||||||
debug CONFIG="\"${CONFIG}\""
|
|
||||||
debug YQ="\"${YAML}\""
|
|
||||||
|
|
||||||
if [[ ! -f ${CONFIG} ]]; then
|
|
||||||
error "config not found."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f ${YAML} ]]; then
|
|
||||||
error "yq not found."
|
|
||||||
fi
|
|
||||||
|
|
||||||
BASE_DIR=$($YAML eval ".BASE_DIR" "${CONFIG}")
|
|
||||||
|
|
||||||
if [[ -v DEBUG && -v BASE_DIR_OVERRIDE ]]; then
|
|
||||||
debug "Overriding $BASE_DIR to $BASE_DIR_OVERRIDE"
|
|
||||||
BASE_DIR="$BASE_DIR_OVERRIDE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
TIMESTAMP=$(date '+%Y-%m-%dT%H:%MZ')
|
|
||||||
|
|
||||||
debug BASE_DIR="\"${BASE_DIR}\""
|
|
||||||
debug TIMESTAMP="\"${TIMESTAMP}\""
|
|
||||||
|
|
||||||
echo Started job $TIMESTAMP..
|
|
||||||
|
|
||||||
cd $BASE_DIR
|
|
||||||
# PRE
|
|
||||||
global_pre_scripts=($(parse_yaml 'global.scripts.pre[]'))
|
|
||||||
for script in "${global_pre_scripts[@]}"; do
|
|
||||||
execute $BASE_DIR/$script
|
|
||||||
done
|
|
||||||
#
|
|
||||||
repos=($(parse_yaml 'global.sync[]'))
|
|
||||||
|
|
||||||
if [[ "${repos[0]}" == "ALL" ]]; then
|
|
||||||
repos=($($YAML eval '.repos | keys | .[]' "${CONFIG}"))
|
|
||||||
fi
|
|
||||||
for repo in "${repos[@]}"; do
|
|
||||||
cd $BASE_DIR
|
|
||||||
debug "Checking $repo..."
|
|
||||||
|
|
||||||
delay=$(get_repo_config ${repo} "delay")
|
|
||||||
last_sync_timestamp=$(date -d "$(get_repo_config ${repo} "last_sync")" +%s)
|
|
||||||
next_sync_timestamp=$(( last_sync_timestamp + delay * 3600 ))
|
|
||||||
|
|
||||||
if [[ -v DEBUG ]]; then
|
|
||||||
next_sync_timestamp=1
|
|
||||||
# read -p "Continue? " choice
|
|
||||||
# case "$choice" in
|
|
||||||
# y) next_sync_timestamp=1;;
|
|
||||||
# *) continue;;
|
|
||||||
# esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $next_sync_timestamp -le $(date +%s) ]; then
|
|
||||||
debug "Lastsync was $last_sync_timestamp."
|
|
||||||
echo "Syncing $repo..."
|
|
||||||
|
|
||||||
repo_pre_scripts=($(get_repo_config ${repo} "scripts.pre[]"))
|
|
||||||
for script in "${repo_pre_scripts[@]}"; do
|
|
||||||
execute $BASE_DIR/$script $repo
|
|
||||||
done
|
|
||||||
|
|
||||||
sync_repo $repo
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
repo_fail_scripts=($(get_repo_config ${repo} "scripts.fail[]"))
|
|
||||||
for script in "${repo_fail_scripts[@]}"; do
|
|
||||||
execute $BASE_DIR/$script $repo
|
|
||||||
done
|
|
||||||
|
|
||||||
global_log_error $repo
|
|
||||||
echo "Error during syncing $repo."
|
|
||||||
else
|
else
|
||||||
|
dist_dir=$dist
|
||||||
global_log $repo
|
|
||||||
$YAML eval ".repos.${repo}.last_sync = \"$TIMESTAMP\"" -i "${CONFIG}"
|
|
||||||
echo "Successfully synced $repo."
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
repo_post_scripts=($(get_repo_config ${repo} "scripts.post[]"))
|
echo ${TIMENOW} >> ${BASE_DIR}/logs/${dist}.log
|
||||||
for script in "${repo_post_scripts[@]}"; do
|
echo ${TIMENOW} >> ${BASE_DIR}/logs/${dist}-error.log
|
||||||
script=${script/\${config\}/$CONFIG}
|
echo "${TIMENOW}: Mirroring ${dist} from ${!dist} to ${DATA_DIR}/${dist}"
|
||||||
execute $BASE_DIR/$script $repo
|
echo "${TIMENOW} STARTED ${dist}" >> ${BASE_DIR}/logs/all.log
|
||||||
done
|
|
||||||
|
TRY=3
|
||||||
|
while [ $TRY -ne 0 ]; do
|
||||||
|
echo Try $TRY...
|
||||||
|
if [ "$dist" == "debian" ];
|
||||||
|
then
|
||||||
|
cd ${BASE_DIR}/scripts
|
||||||
|
export BASE_DIR=${BASE_DIR}
|
||||||
|
export DATA_DIR=${DATA_DIR}
|
||||||
|
./ftpsync
|
||||||
|
else
|
||||||
|
unset RSYNC_CONNECT_PROG
|
||||||
|
if [ "$dist" == "kali_images" ];
|
||||||
|
then
|
||||||
|
# export RSYNC_CONNECT_PROG='ssh zhr0 nc %H 873'
|
||||||
|
echo Connecting to RSYNC PROG
|
||||||
fi
|
fi
|
||||||
|
echo "rsync ${option} ${exclude} ${!dist} ${DATA_DIR}/${dist_dir}" | tee -a ${BASE_DIR}/logs/${dist}.log
|
||||||
|
rsync ${option} ${exclude} ${!dist} ${DATA_DIR}/${dist_dir} 2> >(tee -a ${BASE_DIR}/logs/${dist}-error.log) | tee -a ${BASE_DIR}/logs/${dist}.log
|
||||||
|
EXIT=$?
|
||||||
|
fi
|
||||||
|
if [[ $EXIT == 0 ]]; then break; fi
|
||||||
|
TRY=$(($TRY-1))
|
||||||
done
|
done
|
||||||
|
|
||||||
# POST
|
if [ $EXIT -ne 0 ];
|
||||||
global_post_scripts=($(parse_yaml 'global.scripts.post[]'))
|
then
|
||||||
for script in "${global_post_scripts[@]}"; do
|
MSG="${dist} failed at ${TIMENOW}"
|
||||||
execute $BASE_DIR/$script
|
if [ -f "$ALERT" ];
|
||||||
done
|
then
|
||||||
#
|
${ALERT} "${MSG}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo Sync ${dist} Error
|
||||||
|
echo "${TIMENOW} ERROR ${dist}" >> ${BASE_DIR}/logs/all.log
|
||||||
|
else
|
||||||
|
echo Sync ${dist} Success
|
||||||
|
if [ `echo ${BASE_DIR}/logs/${dist}-error.log | wc -l` -eq 1 ];
|
||||||
|
then
|
||||||
|
rm ${BASE_DIR}/logs/${dist}-error.log
|
||||||
|
fi
|
||||||
|
echo "${TIMENOW} DONE ${dist}" >> ${BASE_DIR}/logs/all.log
|
||||||
|
cd $BASE_DIR
|
||||||
|
echo "Updating Index"
|
||||||
|
python3 -u ./scripts/index.py ${BASE_DIR} ${DATA_DIR}
|
||||||
|
fi
|
||||||
|
|
||||||
echo Ended job $TIMESTAMP..
|
|
|
@ -1,94 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>PAWE.ME</title>
|
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:wght@300;400;500;600;700;800;900&display=swap"
|
|
||||||
rel="stylesheet">
|
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
|
||||||
<script>
|
|
||||||
tailwind.config = {
|
|
||||||
darkMode: 'class'
|
|
||||||
}
|
|
||||||
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
|
||||||
document.documentElement.classList.add('dark')
|
|
||||||
} else {
|
|
||||||
document.documentElement.classList.remove('dark')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style>
|
|
||||||
.url {
|
|
||||||
font-style: italic;
|
|
||||||
color: #5d7abf;
|
|
||||||
|
|
||||||
} </style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="font-sans text-gray-900 bg-gray-100 py-12 px-6 mx-auto max-w-5xl dark:bg-gray-900">
|
|
||||||
<header class="mb-10">
|
|
||||||
<h1 class="text-4xl font-bold mb-2"><a href="http://PAWE.ME/"
|
|
||||||
class="text-blue-500 hover:text-blue-700">PAWE.ME</a></h1>
|
|
||||||
<h2 class="text-lg text-gray-600 dark:text-gray-300">Simple mirroring & archiving server.</h2>
|
|
||||||
<!-- <h2 class="text-lg text-blue-400 dark:text-blue-200 italic"><a href="#">Hide my Email</a>, <a href="#">Invidious</a>, <a href="#">Proxy</a>.</h2> -->
|
|
||||||
</header>
|
|
||||||
<main>
|
|
||||||
<section class="mb-12">
|
|
||||||
<h2 class="dark:text-gray-200 text-2xl font-semibold mb-5">Mirroring List</h2>
|
|
||||||
<div id="mirrorList" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-4">
|
|
||||||
{{ repos }}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="mb-12">
|
|
||||||
<h2 class="dark:text-gray-200 text-2xl font-semibold mb-5">Additional Mirror</h2>
|
|
||||||
<!-- <button onclick="toggleView('httpView')" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mb-4">View More</button> -->
|
|
||||||
<div id="httpView" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-4">
|
|
||||||
{{ repos_more }}
|
|
||||||
|
|
||||||
<div class="bg-white dark:bg-gray-800 col-span-1 md:col-span-2 shadow-lg rounded-lg p-5">
|
|
||||||
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/cd-image"
|
|
||||||
class="text-blue-500 hover:text-blue-700">Image Files</a></h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2 class="dark:text-gray-200 text-2xl font-semibold mb-5">Server Info</h2>
|
|
||||||
<ul class="space-y-2 mb-5">
|
|
||||||
<li class="text-gray-600 dark:text-gray-500">Xeon CPU</li>
|
|
||||||
<li class="text-gray-600 dark:text-gray-500">64GiB Memory</li>
|
|
||||||
<li class="text-gray-600 dark:text-gray-500">1Gbps Network, Seoul, Korea</li>
|
|
||||||
<li class="text-gray-600 dark:text-gray-500">32TB Storage</li>
|
|
||||||
</ul>
|
|
||||||
<p class="text-gray-700 dark:text-gray-400 url">Fill out <a href="/form.html" class="text-blue-600 dark:text-blue-700">this</a> form to request additional mirroring.</p>
|
|
||||||
</section>
|
|
||||||
<button
|
|
||||||
class="fixed bottom-6 right-6 bg-blue-200 hover:bg-blue-300 text-blue-700 dark:bg-blue-800 dark:hover:bg-blue-600 dark:text-white w-10 h-10 rounded-full flex items-center justify-center"
|
|
||||||
onclick="toggleDarkMode()">
|
|
||||||
+
|
|
||||||
</button>
|
|
||||||
</main>
|
|
||||||
<footer class="mt-10 text-center text-gray-600">
|
|
||||||
<a href="mailto:mirror@devpg.net">© PAWE.ME</a>
|
|
||||||
<br/>
|
|
||||||
<a href="https://github.com/morgan9e/pawe.me"><i>source</i></a>
|
|
||||||
</footer>
|
|
||||||
<script>
|
|
||||||
function toggleView(elementId) {
|
|
||||||
const element = document.getElementById(elementId);
|
|
||||||
element.style.display = element.style.display === "none" ? "block" : "none";
|
|
||||||
}
|
|
||||||
function toggleDarkMode() {
|
|
||||||
if (document.documentElement.classList.contains('dark')) {
|
|
||||||
document.documentElement.classList.remove('dark');
|
|
||||||
localStorage.theme = 'light';
|
|
||||||
} else {
|
|
||||||
document.documentElement.classList.add('dark');
|
|
||||||
localStorage.theme = 'dark';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<div class="bg-white dark:bg-gray-800 col-span-1 md:col-span-2 shadow-lg rounded-lg p-5">
|
|
||||||
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/{{path}}"
|
|
||||||
class="text-blue-500 hover:text-blue-700">{{name}}</a></h3>
|
|
||||||
<p class="text-gray-600 dark:text-gray-300">Last Updated: {{lastsync}}</p>
|
|
||||||
<p class="text-gray-600 dark:text-gray-300">Upstream: <span class="url">{{upstream}}</span></p>
|
|
||||||
</div>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<div class="bg-white dark:bg-gray-800 col-span-1 shadow-lg rounded-lg p-5">
|
|
||||||
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/{{path}}"
|
|
||||||
class="text-blue-500 hover:text-blue-700">{{name}}</a></h3>
|
|
||||||
<p class="text-gray-600 dark:text-gray-300">Last Updated: {{lastsync}}</p>
|
|
||||||
<p class="text-gray-600 dark:text-gray-300">Upstream: <span class="url">{{upstream}}</span></p>
|
|
||||||
</div>
|
|
|
@ -1,99 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>repo.city</title>
|
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:wght@300;400;500;600;700;800;900&display=swap"
|
|
||||||
rel="stylesheet">
|
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
|
||||||
<script>
|
|
||||||
tailwind.config = {
|
|
||||||
darkMode: 'class'
|
|
||||||
}
|
|
||||||
// if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
|
||||||
// document.documentElement.classList.add('dark')
|
|
||||||
if (localStorage.theme === 'dark') {
|
|
||||||
document.documentElement.classList.add('dark')
|
|
||||||
} else {
|
|
||||||
document.documentElement.classList.remove('dark')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style>
|
|
||||||
.url {
|
|
||||||
font-style: italic;
|
|
||||||
color: rgb(86, 105, 151);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="font-sans text-gray-900 bg-gray-100 py-12 px-6 mx-auto max-w-5xl dark:bg-gray-900">
|
|
||||||
<header class="mb-10 ml-2">
|
|
||||||
<h1 class="text-3xl font-bold mb-2 text-black dark:text-white">Welcome to <a href="https://repo.city"
|
|
||||||
class="text-blue-900 dark:text-blue-300 font-bold">REPO.CITY</a>!</h1>
|
|
||||||
<h2 class="text-xl text-gray-600 dark:text-gray-300">Simple mirroring & archiving server.</h2>
|
|
||||||
</header>
|
|
||||||
<main>
|
|
||||||
<section class="mb-12">
|
|
||||||
<h2 class="dark:text-gray-200 text-2xl font-semibold mb-5 ml-2">Mirroring List</h2>
|
|
||||||
<div id="mirrorList" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-4">
|
|
||||||
|
|
||||||
{{ repos }}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</section>
|
|
||||||
<section class="mb-12">
|
|
||||||
<h2 class="dark:text-gray-200 text-2xl font-semibold mb-5 ml-2">Additional Mirror</h2>
|
|
||||||
<!-- <button onclick="toggleView('httpView')" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mb-4">View More</button> -->
|
|
||||||
<div id="httpView" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-4">
|
|
||||||
|
|
||||||
{{ repos_more }}
|
|
||||||
|
|
||||||
<div class="bg-white dark:bg-gray-800 col-span-1 md:col-span-2 shadow-lg rounded-lg p-5">
|
|
||||||
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/cd-image"
|
|
||||||
class="text-blue-900 hover:text-blue-600 dark:text-blue-600 dark:hover:text-blue-400">Image Files</a></h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="ml-2">
|
|
||||||
<h2 class="dark:text-gray-200 text-2xl font-semibold mb-4">Server Details</h2>
|
|
||||||
<p class="mb-2 text-gray-800 dark:text-gray-500"><strong>Location:</strong> Seoul, Korea</p>
|
|
||||||
<p class="mb-2 text-gray-800 dark:text-gray-500"><strong>Bandwidth:</strong> ~1Gbps</p>
|
|
||||||
<p class="mb-2 text-gray-800 dark:text-gray-500"><strong>Storage size:</strong> 32TiB</p>
|
|
||||||
<p class="mb-2 text-gray-800 dark:text-gray-500"><strong>Sync delay:</strong> 4hrs</p>
|
|
||||||
<p class="mb-2 text-gray-800 dark:text-gray-500"><strong>Contact:</strong> <a href="mailto:mirror@devpg.net">mirror@devpg.net</a></p>
|
|
||||||
<p class="mb-2 text-gray-800 dark:text-gray-500"><strong>Maintainer:</strong> <a href="https://github.com/morgan9e">@morgan9e</a></p>
|
|
||||||
<p class="text-gray-500 dark:text-gray-600 url">This mirror is based on <a href="https://github.com/morgan9e/reposync" class="text-blue-500 dark:text-blue-800">reposync</a>.</p>
|
|
||||||
<p class="text-gray-500 dark:text-gray-600 url">For additional mirroring requests, please contact me at email above.</p>
|
|
||||||
</section>
|
|
||||||
<button
|
|
||||||
class="fixed bottom-6 right-6 bg-blue-200 hover:bg-blue-300 text-blue-700 dark:bg-blue-800 dark:hover:bg-blue-600 dark:text-white w-10 h-10 rounded-full flex items-center justify-center"
|
|
||||||
onclick="toggleDarkMode()">
|
|
||||||
+
|
|
||||||
</button>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer class="mt-10 text-center text-gray-600">
|
|
||||||
<a href="mailto:mirror@devpg.net">© REPO.CITY</a>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function toggleView(elementId) {
|
|
||||||
const element = document.getElementById(elementId);
|
|
||||||
element.style.display = element.style.display === "none" ? "block" : "none";
|
|
||||||
}
|
|
||||||
function toggleDarkMode() {
|
|
||||||
if (document.documentElement.classList.contains('dark')) {
|
|
||||||
document.documentElement.classList.remove('dark');
|
|
||||||
localStorage.theme = 'light';
|
|
||||||
} else {
|
|
||||||
document.documentElement.classList.add('dark');
|
|
||||||
localStorage.theme = 'dark';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<div class="bg-white dark:bg-gray-800 col-span-1 md:col-span-2 shadow-lg rounded-lg p-5">
|
|
||||||
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/{{path}}"
|
|
||||||
class="text-blue-900 hover:text-blue-600 dark:text-blue-600 dark:hover:text-blue-400">{{name}}</a></h3>
|
|
||||||
<p class="text-gray-600 dark:text-gray-300">Last Updated: {{lastsync}}</p>
|
|
||||||
<p class="text-gray-600 dark:text-gray-300">Upstream: <span class="url">{{upstream}}</span></p>
|
|
||||||
</div>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<div class="bg-white dark:bg-gray-800 col-span-1 shadow-lg rounded-lg p-5">
|
|
||||||
<h3 class="dark:text-white text-lg font-semibold mb-1"><a href="/{{path}}"
|
|
||||||
class="text-blue-900 hover:text-blue-600 dark:text-blue-600 dark:hover:text-blue-400">{{name}}</a></h3>
|
|
||||||
<p class="text-gray-600 dark:text-gray-300">Last Updated: {{lastsync}}</p>
|
|
||||||
<p class="text-gray-600 dark:text-gray-300">Upstream: <span class="url">{{upstream}}</span></p>
|
|
||||||
</div>
|
|
BIN
scripts/yq
BIN
scripts/yq
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 40 KiB |
|
@ -1,77 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>PAWE.ME</title>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:wght@300;400;500;600;700;800;900&display=swap"
|
|
||||||
rel="stylesheet">
|
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
|
||||||
<style>
|
|
||||||
.url {
|
|
||||||
font-style: italic;
|
|
||||||
color: rgb(86, 105, 151);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body class="font-sans text-gray-900 bg-gray-100 py-12 px-6 mx-auto max-w-5xl">
|
|
||||||
<header class="mb-10">
|
|
||||||
<h1 class="text-4xl font-bold mb-2"><a href="http://PAWE.ME" class="text-blue-500 hover:text-blue-700">PAWE.ME</a></h1>
|
|
||||||
<h2 class="text-lg text-gray-600"></h2>
|
|
||||||
</header>
|
|
||||||
<form id="contactForm" class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
|
|
||||||
<h2 class="text-2xl font-semibold mb-5">Request Form</h2>
|
|
||||||
<div class="mb-4">
|
|
||||||
<label class="block text-gray-700 text-sm font-bold mb-2" for="email">
|
|
||||||
Email
|
|
||||||
</label>
|
|
||||||
<input class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="email" type="email" placeholder="Email">
|
|
||||||
</div>
|
|
||||||
<div class="mb-4 hidden">
|
|
||||||
<label class="block text-gray-700 text-sm font-bold mb-2" for="title">
|
|
||||||
Title
|
|
||||||
</label>
|
|
||||||
<input class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="title" type="text" placeholder="Title" value="New Request">
|
|
||||||
</div>
|
|
||||||
<div class="mb-6">
|
|
||||||
<label class="block text-gray-700 text-sm font-bold mb-2" for="content">
|
|
||||||
Content
|
|
||||||
</label>
|
|
||||||
<textarea class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="content" placeholder="Content" rows="5"></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<button id="sendButton" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="button">
|
|
||||||
Send Message
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<p class="text-gray-800 text-xs italic"> Only Rsync & HTTP File server is available. HTTP mirroring cycle is much slower than Rsync. Feel free to request!</p>
|
|
||||||
<script>
|
|
||||||
document.getElementById('sendButton').addEventListener('click', function() {
|
|
||||||
const email = document.getElementById('email').value;
|
|
||||||
const title = document.getElementById('title').value;
|
|
||||||
const content = document.getElementById('content').value;
|
|
||||||
|
|
||||||
let formData = new URLSearchParams();
|
|
||||||
formData.append('email', email);
|
|
||||||
formData.append('title', title);
|
|
||||||
formData.append('content', content);
|
|
||||||
|
|
||||||
fetch(PUSHAPIADDRESS, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
},
|
|
||||||
body: formData.toString(),
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then((data) => {
|
|
||||||
console.log(data);
|
|
||||||
alert("Sent to Administrator. Reply may take 2-3 days.");
|
|
||||||
})
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../index.html
|
|
|
@ -1,70 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Log Viewer</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<input type="text" id="logPath" placeholder="Enter log file path or URL">
|
|
||||||
<select id="intervalSelector">
|
|
||||||
<option value="1000">1 sec</option>
|
|
||||||
<option value="2000">2 sec</option>
|
|
||||||
<option value="3000">3 sec</option>
|
|
||||||
</select>
|
|
||||||
<button onclick="startFetchingLog()">Start Fetching</button>
|
|
||||||
<button onclick="toggleFetching()">Toggle Fetching</button>
|
|
||||||
|
|
||||||
<div id="logContent" style="white-space: pre-wrap;"></div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
let interval;
|
|
||||||
let isFetching = false;
|
|
||||||
|
|
||||||
function fetchLog(path) {
|
|
||||||
fetch(path)
|
|
||||||
.then(response => response.text())
|
|
||||||
.then(data => {
|
|
||||||
const reversedData = data.split("\n").reverse().join("\n");
|
|
||||||
document.getElementById('logContent').textContent = reversedData;
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('There was an error fetching the log:', error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function startFetchingLog() {
|
|
||||||
stopFetching(); // Stop any existing fetching
|
|
||||||
|
|
||||||
const path = document.getElementById('logPath').value;
|
|
||||||
const fetchInterval = parseInt(document.getElementById('intervalSelector').value);
|
|
||||||
if (path) {
|
|
||||||
fetchLog(path); // Initial fetch
|
|
||||||
interval = setInterval(() => fetchLog(path), fetchInterval); // Fetch the log file at the selected interval
|
|
||||||
isFetching = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopFetching() {
|
|
||||||
if (interval) {
|
|
||||||
clearInterval(interval);
|
|
||||||
isFetching = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleFetching() {
|
|
||||||
if (isFetching) {
|
|
||||||
stopFetching();
|
|
||||||
} else {
|
|
||||||
startFetchingLog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
Loading…
Reference in New Issue