feat: add shard status page
This commit is contained in:
		@@ -25,7 +25,7 @@
 | 
				
			|||||||
    "discord-markdown": "^2.5.1",
 | 
					    "discord-markdown": "^2.5.1",
 | 
				
			||||||
    "gh-pages": "^3.2.3",
 | 
					    "gh-pages": "^3.2.3",
 | 
				
			||||||
    "moment": "^2.29.1",
 | 
					    "moment": "^2.29.1",
 | 
				
			||||||
    "sass": "^1.45.1",
 | 
					    "sass": "^1.47.0",
 | 
				
			||||||
    "svelecte": "^3.4.5",
 | 
					    "svelecte": "^3.4.5",
 | 
				
			||||||
    "svelte-autosize": "^1.0.1",
 | 
					    "svelte-autosize": "^1.0.1",
 | 
				
			||||||
    "svelte-icons": "^2.1.0",
 | 
					    "svelte-icons": "^2.1.0",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@
 | 
				
			|||||||
  import Footer from './lib/Footer.svelte';
 | 
					  import Footer from './lib/Footer.svelte';
 | 
				
			||||||
  import Public from "./pages/Public.svelte";
 | 
					  import Public from "./pages/Public.svelte";
 | 
				
			||||||
  import Main from "./pages/profiles/Main.svelte";
 | 
					  import Main from "./pages/profiles/Main.svelte";
 | 
				
			||||||
 | 
					  import Status from './pages/status.svelte';
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  // theme cdns (I might make some myself too)
 | 
					  // theme cdns (I might make some myself too)
 | 
				
			||||||
  let light = "https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css";
 | 
					  let light = "https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css";
 | 
				
			||||||
@@ -64,5 +65,6 @@
 | 
				
			|||||||
    <Route path = "profile/g">
 | 
					    <Route path = "profile/g">
 | 
				
			||||||
      hey please provide a group
 | 
					      hey please provide a group
 | 
				
			||||||
    </Route>
 | 
					    </Route>
 | 
				
			||||||
 | 
					    <Route path="status"><Status /></Route>
 | 
				
			||||||
  <Footer />
 | 
					  <Footer />
 | 
				
			||||||
</Router>
 | 
					</Router>
 | 
				
			||||||
							
								
								
									
										89
									
								
								src/lib/shard.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/lib/shard.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
						let isHovering = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						export let shard = {
 | 
				
			||||||
 | 
							id: 1,
 | 
				
			||||||
 | 
							status: "",
 | 
				
			||||||
 | 
							ping:0,
 | 
				
			||||||
 | 
							last_connection:0,
 | 
				
			||||||
 | 
							last_heartbeat:0.
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						let color = "background-color: #fff";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// shard is down
 | 
				
			||||||
 | 
						// todo: check if last heartbeat is really recent, since database up/down status can get out of sync
 | 
				
			||||||
 | 
						if (shard.status != "up") color = "background-color: #000;";
 | 
				
			||||||
 | 
						// shard latency is < 250ms: OK!
 | 
				
			||||||
 | 
						else if (shard.ping < 300) color = "background-color: #00cc00;";
 | 
				
			||||||
 | 
						// shard latency is 250ms < ping < 600ms: slow, but OK
 | 
				
			||||||
 | 
						else if (shard.ping < 600) color = "background-color: #da9317;";
 | 
				
			||||||
 | 
						// shard latency is >600ms, this might be problematic
 | 
				
			||||||
 | 
						else color = "background-color: #cc0000;"
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="wrapper">
 | 
				
			||||||
 | 
						<div
 | 
				
			||||||
 | 
							on:click={() => isHovering = !isHovering}
 | 
				
			||||||
 | 
							class="shard" id={shard.id.toString()}
 | 
				
			||||||
 | 
							style={color}
 | 
				
			||||||
 | 
						>{ shard.id }</div>
 | 
				
			||||||
 | 
						{#if isHovering}
 | 
				
			||||||
 | 
							<div class="more-info">
 | 
				
			||||||
 | 
								<h3>Shard { shard.id }</h3>
 | 
				
			||||||
 | 
								<br>
 | 
				
			||||||
 | 
								<span>Status: <b>{ shard.status }</b></span><br>
 | 
				
			||||||
 | 
								<span>Latency: { shard.ping }ms</span><br>
 | 
				
			||||||
 | 
								<span>Last connection: { new Date(shard.last_connection).toUTCString().match(/([0-9][0-9]:[0-9][0-9]:[0-9][0-9])/)?.shift() }</span><br>
 | 
				
			||||||
 | 
								<span>Last heartbeat: { new Date(shard.last_heartbeat).toUTCString().match(/([0-9][0-9]:[0-9][0-9]:[0-9][0-9])/)?.shift() }</span><br>
 | 
				
			||||||
 | 
								<br>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
						{/if}
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
						.wrapper {
 | 
				
			||||||
 | 
							height: 55px;
 | 
				
			||||||
 | 
							width: 55px;
 | 
				
			||||||
 | 
							display: block;
 | 
				
			||||||
 | 
							float: left;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						.shard {
 | 
				
			||||||
 | 
							color: #fff;
 | 
				
			||||||
 | 
							display: block;
 | 
				
			||||||
 | 
							float: left;
 | 
				
			||||||
 | 
							display: flex;
 | 
				
			||||||
 | 
							flex-direction: column;
 | 
				
			||||||
 | 
							align-items: center;
 | 
				
			||||||
 | 
							text-align: center;
 | 
				
			||||||
 | 
							justify-content: center;
 | 
				
			||||||
 | 
							z-index: 1;
 | 
				
			||||||
 | 
							height: 50px;
 | 
				
			||||||
 | 
							width: 50px;
 | 
				
			||||||
 | 
							margin-right: 5px;
 | 
				
			||||||
 | 
							margin-bottom: 5px;
 | 
				
			||||||
 | 
							border-radius: 2px;
 | 
				
			||||||
 | 
							-webkit-touch-callout: none; /* iOS Safari */
 | 
				
			||||||
 | 
							  -webkit-user-select: none; /* Safari */
 | 
				
			||||||
 | 
							   -khtml-user-select: none; /* Konqueror HTML */
 | 
				
			||||||
 | 
								 -moz-user-select: none; /* Old versions of Firefox */
 | 
				
			||||||
 | 
								  -ms-user-select: none; /* Internet Explorer/Edge */
 | 
				
			||||||
 | 
									  user-select: none; /* Non-prefixed version, currently
 | 
				
			||||||
 | 
															supported by Chrome, Edge, Opera and Firefox */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						.more-info {
 | 
				
			||||||
 | 
							/* display: none; */
 | 
				
			||||||
 | 
							position: absolute;
 | 
				
			||||||
 | 
							margin-top: 3em;
 | 
				
			||||||
 | 
							will-change: transform;
 | 
				
			||||||
 | 
							min-height: 150px;
 | 
				
			||||||
 | 
							width: 200px;
 | 
				
			||||||
 | 
							z-index: 2;
 | 
				
			||||||
 | 
							border-radius: 5px;
 | 
				
			||||||
 | 
							background-color: #333;
 | 
				
			||||||
 | 
							color: #fff;
 | 
				
			||||||
 | 
							opacity: 95%;
 | 
				
			||||||
 | 
							text-align: center;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 | 
						
 | 
				
			||||||
							
								
								
									
										117
									
								
								src/pages/status.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/pages/status.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
				
			|||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					    import { Container } from 'sveltestrap';
 | 
				
			||||||
 | 
					    import ShardItem from '../lib/shard.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let message = "Loading...";
 | 
				
			||||||
 | 
					    let shards = [];
 | 
				
			||||||
 | 
					    let pingAverage = "";
 | 
				
			||||||
 | 
					    let currentCommitMsg = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let foundShard = {
 | 
				
			||||||
 | 
					        id: 1,
 | 
				
			||||||
 | 
					        status: 1,
 | 
				
			||||||
 | 
					        ping:"",
 | 
				
			||||||
 | 
					        last_connection:0,
 | 
				
			||||||
 | 
					        last_heartbeat:0.
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    foundShard = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let findShardInput = "";
 | 
				
			||||||
 | 
					    let valid = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const get = async () => {
 | 
				
			||||||
 | 
					        const pkdata = await fetch("https://api.pluralkit.me/v1/meta").then(x => x.json());
 | 
				
			||||||
 | 
					            shards = pkdata.shards.sort((x, y) => (x.id > y.id) ? 1 : -1);
 | 
				
			||||||
 | 
					            let pings = 0;
 | 
				
			||||||
 | 
					            shards = shards.map(shard => {
 | 
				
			||||||
 | 
					                    shard.ping = Math.trunc(shard.ping * 1000);
 | 
				
			||||||
 | 
					                    pings += shard.ping;
 | 
				
			||||||
 | 
					                    return shard;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					            pingAverage = Math.trunc(pings / shards.length).toString();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					            currentCommitMsg = `Current Git commit: <a href="https://github.com/xSke/PluralKit/commit/${pkdata.version}">${pkdata.version}</a>`;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					            message = "";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get();
 | 
				
			||||||
 | 
					    setTimeout(get, 30 * 1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // javascript wants everything to be BigInts
 | 
				
			||||||
 | 
					    const getShardID = (guild_id: string, num_shards: number) => guild_id == "" ? -1 : (BigInt(guild_id) >> BigInt(22)) % BigInt(num_shards);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    let shardInfoMsg = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let shardInfoHandler = (_: Event) => {
 | 
				
			||||||
 | 
					        if (findShardInput == "" || !findShardInput) {
 | 
				
			||||||
 | 
					            valid = false;
 | 
				
			||||||
 | 
					            foundShard = null;
 | 
				
			||||||
 | 
					            shardInfoMsg = "";
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        var match = findShardInput.match(/https:\/\/[\w+]?discord[app]?.com\/channels\/(\d+)\/\d+\/\d+/);
 | 
				
			||||||
 | 
					        if (match != null) {
 | 
				
			||||||
 | 
					            console.log("match", match)
 | 
				
			||||||
 | 
					            foundShard = shards[Number(getShardID(match[1], shards.length))];
 | 
				
			||||||
 | 
					            valid = true;
 | 
				
			||||||
 | 
					            shardInfoMsg = "";
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            var shard = getShardID(findShardInput, shards.length);
 | 
				
			||||||
 | 
					            if (shard == -1) {
 | 
				
			||||||
 | 
					                valid = false;
 | 
				
			||||||
 | 
					                foundShard == null;
 | 
				
			||||||
 | 
					                shardInfoMsg = "Invalid server ID";
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            foundShard = shards[Number(shard)];
 | 
				
			||||||
 | 
					            valid = true;
 | 
				
			||||||
 | 
					            shardInfoMsg = "";
 | 
				
			||||||
 | 
					        } catch(e) {
 | 
				
			||||||
 | 
					            valid = false;
 | 
				
			||||||
 | 
					            shardInfoMsg = "Invalid server ID";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<Container>
 | 
				
			||||||
 | 
					    <h1>Bot status</h1>
 | 
				
			||||||
 | 
					    <span>{@html currentCommitMsg}</span>
 | 
				
			||||||
 | 
					    <br>
 | 
				
			||||||
 | 
					    <noscript>Please enable JavaScript to view this page!</noscript>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    { shards.length } shards ({ shards.filter(x => x.status == "up").length } up) <br>
 | 
				
			||||||
 | 
					    Average latency: { pingAverage }ms
 | 
				
			||||||
 | 
					    <br><br>
 | 
				
			||||||
 | 
					    All times in UTC. More statistics available at <a href="https://stats.pluralkit.me">https://stats.pluralkit.me</a>
 | 
				
			||||||
 | 
					    <br><br>
 | 
				
			||||||
 | 
					    <details>
 | 
				
			||||||
 | 
					        <summary><b>Find my shard</b></summary>
 | 
				
			||||||
 | 
					        <br>
 | 
				
			||||||
 | 
					        Enter a server ID or a message link to find the shard currently assigned to your server:
 | 
				
			||||||
 | 
					        <br>
 | 
				
			||||||
 | 
					        <input bind:value={findShardInput} on:input={shardInfoHandler} />
 | 
				
			||||||
 | 
					        <br><br>
 | 
				
			||||||
 | 
					        <span>{ shardInfoMsg }</span>
 | 
				
			||||||
 | 
					        {#if valid}
 | 
				
			||||||
 | 
					            <h3>Your shard is: Shard { foundShard.id }</h3>
 | 
				
			||||||
 | 
					            <br>
 | 
				
			||||||
 | 
					            <span>Status: <b>{ foundShard.status }</b></span><br>
 | 
				
			||||||
 | 
					            <span>Latency: { foundShard.ping }ms</span><br>
 | 
				
			||||||
 | 
					            <span>Last connection: { new Date(foundShard.last_connection).toUTCString()?.match(/([0-9][0-9]:[0-9][0-9]:[0-9][0-9])/)?.shift() }</span><br>
 | 
				
			||||||
 | 
					            <span>Last heartbeat: { new Date(foundShard.last_heartbeat).toUTCString().match(/([0-9][0-9]:[0-9][0-9]:[0-9][0-9])/)?.shift() }</span><br>
 | 
				
			||||||
 | 
					        {/if}
 | 
				
			||||||
 | 
					    </details>
 | 
				
			||||||
 | 
					    <br><br>
 | 
				
			||||||
 | 
					    <h2>Shard status</h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <span>{ message }</span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {#each shards as shard}
 | 
				
			||||||
 | 
					        <ShardItem shard={shard} />
 | 
				
			||||||
 | 
					    {/each}
 | 
				
			||||||
 | 
					</Container>
 | 
				
			||||||
		Reference in New Issue
	
	Block a user