├── LICENSE ├── README.md ├── config.json ├── db ├── database.json └── logs.json ├── index.js ├── package.json ├── replit.nix └── web ├── public ├── script.js └── style.css └── views └── index.ejs /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Vusal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Status Page v2.0 2 | Basic status page for your websites. v2.0 3 | 4 | ### Example 5 | [status.vsldev.tk](https://status.vsldev.tk) 6 | 7 | # Copyright! 8 | It is forbidden to delete the footer part below! If those who do are detected, good things will not happen :) 9 | 10 |  11 | 12 | # Setup 13 | Add your links as you can see in the image and run it, nothing will happen on the screen at first, but everything will be fine in 10 to 15 minutes. 14 | 15 |  16 | 17 | # Screenshots 18 | 19 |  20 | 21 | 22 | # Links 23 | 24 | - Website - [vsldev.tk](https://vsldev.tk) 25 | - Instagram - [vsl.dev](https://vsldev.tk/instagram) 26 | - Github - [vsl-dev](https://vsldev.tk/github) 27 | - Discord - [VSL | Offical Server](https://vsldev.tk/discord) 28 | - Other Links - [vsldev.tk/links](https://vsldev.tk/links) 29 | 30 | # Support 31 | 32 | [Support & Feedback](https://vsldev.tk/discord) 33 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "refresh_time": "300000", 3 | "links": { 4 | "1": { 5 | "link_id": "1", 6 | "link": "https://vslapi.cf" 7 | }, 8 | "2": { 9 | "link_id": "2", 10 | "link": "https://vsldev.tk" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /db/database.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /db/logs.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyparser = require("body-parser"); 3 | const session = require("express-session"); 4 | const path = require("path"); 5 | const ejs = require("ejs"); 6 | const url = require("url"); 7 | const rateLimit = require("express-rate-limit") 8 | const moment = require('moment') 9 | var momento = require('moment-timezone'); 10 | const axios = require("axios") 11 | const request = require('request') 12 | const app = express(); 13 | var clc = require("cli-color"); 14 | const config = require('./config.json') 15 | const now = moment().format("YYYY, MM, DD, HH:mm") 16 | const port = 8080 17 | const { 18 | JsonDatabase 19 | } = require("wio.db"); 20 | const db = new JsonDatabase({ 21 | databasePath: "./db/database.json" 22 | }); 23 | const log = new JsonDatabase({ 24 | databasePath: "./db/logs.json" 25 | }); 26 | 27 | // View engines & others 28 | 29 | app.use(bodyparser.json()); 30 | app.use(bodyparser.urlencoded({ extended: true })); 31 | app.engine("html", ejs.renderFile); 32 | app.set('view engine', 'ejs'); 33 | app.set('views', path.join(__dirname, "/web/views")); 34 | app.use(express.static(path.join(__dirname, "/web/public"))); 35 | app.set('json spaces', 1) 36 | 37 | // Pages 38 | 39 | app.get('/', (req, res) => { 40 | const vsl = Object.values(config.links) 41 | res.render('index', { 42 | user: req.user, 43 | config, req, vsl, db, moment, log 44 | }) 45 | }) 46 | 47 | setInterval(() => { 48 | var links = config.links; 49 | if (!links) return; 50 | var linkA = Object.values(links) 51 | var lnks = linkA.map(c => c); 52 | lnks.forEach(link => { 53 | request(link.link, function (error, response) { 54 | console.log(link) 55 | console.error('error:', error); 56 | console.log('statusCode:', response && response.statusCode); 57 | if(error == null) { 58 | var Data = { 59 | "last_req": now, 60 | "status_code": response.statusCode, 61 | "error": false 62 | } 63 | var LogData = { 64 | "id": link.link_id, 65 | "last_req": now, 66 | "status_code": response.statusCode, 67 | "error": false 68 | } 69 | } else { 70 | var Data = { 71 | "last_req": now, 72 | "status_code": 999, 73 | "error": true 74 | } 75 | var LogData = { 76 | "id": link.link_id, 77 | "last_req": now, 78 | "status_code": 999, 79 | "error": true 80 | } 81 | } 82 | db.add('requests.total', 1) 83 | db.set(`requests.${link.link_id}`, Data) 84 | log.push(`${link.link_id}`, LogData) 85 | 86 | }); 87 | }); 88 | }, config.refresh_time) 89 | 90 | // random string generator 91 | 92 | function randomstring(length) { 93 | var result = ''; 94 | var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 95 | var charactersLength = characters.length; 96 | for (var i = 0; i < length; i++) { 97 | result += characters.charAt(Math.floor(Math.random() * 98 | charactersLength)); 99 | } 100 | return result; 101 | } 102 | 103 | // Other 104 | 105 | app.listen(port, () => { 106 | console.log('[System Manager]: System running on port ' + port) 107 | console.log('[System Manager]: https://github.com/vsl-dev') 108 | }) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "axios": "^0.27.2", 4 | "body-parser": "^1.20.0", 5 | "cli-color": "^2.0.2", 6 | "ejs": "^3.1.8", 7 | "express": "^4.18.1", 8 | "express-rate-limit": "^6.4.0", 9 | "express-session": "^1.17.3", 10 | "moment": "^2.29.3", 11 | "moment-timezone": "^0.5.34", 12 | "path": "^0.12.7", 13 | "request": "^2.88.2", 14 | "url": "^0.11.0", 15 | "wio.db": "^4.0.22" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /replit.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: { 2 | deps = with pkgs; [ 3 | nodejs-16_x 4 | nodePackages.typescript-language-server 5 | ]; 6 | } -------------------------------------------------------------------------------- /web/public/script.js: -------------------------------------------------------------------------------- 1 | // Loading Section 2 | 3 | setTimeout(() => { 4 | document.querySelector('#loading_wrapper').style.display = 'none'; 5 | }, 1350); 6 | -------------------------------------------------------------------------------- /web/public/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Nunito&display=swap'); 2 | 3 | body { 4 | background-color: #D1D8EC; 5 | font-family: 'Nunito', sans-serif; 6 | transition: .25s; 7 | } 8 | 9 | .unselectable { 10 | user-drag: none; 11 | user-select: none; 12 | -moz-user-select: none; 13 | -webkit-user-drag: none; 14 | -webkit-user-select: none; 15 | -ms-user-select: none; 16 | } 17 | 18 | .head { 19 | margin: 70px 0 0 0; 20 | padding: 20px; 21 | width: 70%; 22 | height: auto!important; 23 | border-radius: 20px; 24 | background: #D1D8EC; 25 | box-shadow: 12px 12px 24px #b2b8c9, -12px -12px 24px #f0f8ff; 26 | transition: .25s; 27 | } 28 | 29 | .status__page { 30 | margin: 70px 0 0 0; 31 | padding: 25px; 32 | width: 70%; 33 | height: auto!important; 34 | border-radius: 20px; 35 | background: #D1D8EC; 36 | box-shadow: 12px 12px 24px #b2b8c9, -12px -12px 24px #f0f8ff; 37 | transition: .25s; 38 | } 39 | 40 | .container { 41 | display: flex; 42 | flex-wrap: wrap; 43 | max-width: 1200px; 44 | } 45 | 46 | .card { 47 | padding: 20px 0 0 25px; 48 | display: flex; 49 | flex-direction: row; 50 | width: 100%; 51 | overflow: hidden; 52 | background-color: transparent; 53 | } 54 | 55 | .card:nth-child(1) { 56 | padding: 0 0 0 25px; 57 | } 58 | 59 | .status { 60 | cursor: pointer; 61 | display: flex; 62 | flex-direction: row; 63 | width: 10px; 64 | height: 28px; 65 | background-color: gray; 66 | border-radius: 3px; 67 | padding: 3px; 68 | margin: 3px; 69 | transition: .25s; 70 | } 71 | 72 | .status:hover { 73 | transition: .25s; 74 | transform: translateY(-3px); 75 | } 76 | 77 | .footer { 78 | text-align: center; 79 | } 80 | 81 | .footer a { 82 | color: black; 83 | text-decoration: none; 84 | } 85 | 86 | .tooltip { 87 | position: relative; 88 | display: inline-block; 89 | } 90 | 91 | .tooltip .tooltiptext { 92 | visibility: hidden; 93 | width: 120px; 94 | background-color: black; 95 | opacity: 95%; 96 | color: #fff; 97 | text-align: center; 98 | border-radius: 6px; 99 | padding: 5px 0; 100 | position: absolute; 101 | z-index: 1; 102 | bottom: 120%; 103 | left: 50%; 104 | margin-left: -60px; 105 | } 106 | 107 | .tooltip .tooltiptext::after { 108 | content: ""; 109 | position: absolute; 110 | top: 100%; 111 | left: 50%; 112 | margin-left: -5px; 113 | border-width: 5px; 114 | border-style: solid; 115 | border-color: black transparent transparent transparent; 116 | } 117 | 118 | .tooltip:hover .tooltiptext { 119 | visibility: visible; 120 | } 121 | 122 | /* Loading */ 123 | 124 | #loading_wrapper { 125 | position: fixed; 126 | top: 0; 127 | right: 0; 128 | bottom: 0; 129 | left: 0; 130 | background-color: transparent; 131 | backdrop-filter: blur(20px); 132 | transition: .25s ease; 133 | z-index: 9999; 134 | } 135 | 136 | #loading_wrapper p { 137 | position: absolute; 138 | top: 45%; 139 | left: 50%; 140 | transform: translate(-50%, -50%); 141 | transition: .25s ease; 142 | z-index: 99999; 143 | } 144 | 145 | @media only screen and (max-width: 600px), (max-width: 700px), (max-width: 800px), (max-width: 900px) { 146 | 147 | .status { 148 | cursor: pointer; 149 | display: flex; 150 | flex-direction: row; 151 | width: 3px; 152 | height: 18px; 153 | background-color: gray; 154 | border-radius: 3px; 155 | padding: 3px; 156 | margin: 1px; 157 | transition: .25s; 158 | } 159 | 160 | } -------------------------------------------------------------------------------- /web/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |Loading...
24 |<% if(db.fetch(`requests.${x.link_id}`).status_code == 200) { %> <%= x.link %>
<% } else { %> <%= x.link %> 47 | 48 | <% }} else { %><% } %> 49 | 50 | <% } else { %> 51 | 52 | <% } %> 53 |