Skip to content
This repository has been archived by the owner on Aug 1, 2022. It is now read-only.

Network diagnostics #1758

Merged
merged 2 commits into from
May 25, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@
"radicle-contracts": "github:radicle-dev/radicle-contracts#commit=752cf0767c6ba7428c626abf91ae1874de613f26",
"semver": "^7.3.5",
"stream-browserify": "^3.0.0",
"svelte-json-tree": "^0.1.0",
"svelte-persistent-store": "^0.1.6",
"timeago.js": "^4.0.2",
"twemoji": "13.0.2",
Expand Down
4 changes: 2 additions & 2 deletions proxy/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ warp = { version = "0.3", default-features = false }

[dependencies.radicle-daemon]
git = "https://github.com/radicle-dev/radicle-link.git"
rev = "49562b86e14889bbf8f96d846d46d94bc32468c0"
rev = "f9fa8303cd33096d7818f0dcb0a24d3a9f618fab"

[dependencies.radicle-git-ext]
git = "https://github.com/radicle-dev/radicle-link.git"
rev = "49562b86e14889bbf8f96d846d46d94bc32468c0"
rev = "f9fa8303cd33096d7818f0dcb0a24d3a9f618fab"

[dependencies.radicle-avatar]
git = "https://github.com/radicle-dev/radicle-avatar.git"
Expand Down
51 changes: 51 additions & 0 deletions proxy/api/src/notification.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
//! Machinery to signal significant events to clients.

use radicle_daemon::request::{RequestState, SomeRequest, Status as PeerRequestStatus};
use radicle_git_ext::Oid;
use std::{
collections::HashMap,
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
time::SystemTime,
};

use serde::Serialize;
Expand Down Expand Up @@ -63,6 +66,12 @@ pub enum LocalPeer {
/// The new [`PeerStatus`].
new: PeerStatus,
},
WaitingRoomTransition {
event: radicle_daemon::peer::WaitingRoomEvent,
state_before: SerializableWaitingRoomState,
state_after: SerializableWaitingRoomState,
timestamp: u128,
},
}

#[allow(clippy::wildcard_enum_match_arm)]
Expand Down Expand Up @@ -90,6 +99,18 @@ impl MaybeFrom<PeerEvent> for Notification {
PeerEvent::StatusChanged { old, new } => {
Some(Self::LocalPeer(LocalPeer::StatusChanged { old, new }))
},
PeerEvent::WaitingRoomTransition(t) => {
let since_the_epoch = t
.timestamp
.duration_since(std::time::UNIX_EPOCH)
.expect("Time went backwards");
Some(Self::LocalPeer(LocalPeer::WaitingRoomTransition {
event: t.event,
state_before: t.state_before.into(),
state_after: t.state_after.into(),
timestamp: since_the_epoch.as_millis(),
}))
},
_ => None,
}
}
Expand Down Expand Up @@ -129,3 +150,33 @@ impl Subscriptions {
receiver
}
}

#[derive(Clone, Debug, Serialize)]
pub struct SerializableWaitingRoomState(HashMap<String, SerializedRequestState>);

#[derive(Debug, Clone, Serialize)]
pub struct SerializedRequestState {
state: String,
peers: HashMap<PeerId, PeerRequestStatus>,
}

impl From<HashMap<Oid, SomeRequest<SystemTime>>> for SerializableWaitingRoomState {
fn from(raw: HashMap<Oid, SomeRequest<SystemTime>>) -> Self {
let inner: HashMap<String, SerializedRequestState> = raw
.iter()
.map(|(urn, request)| {
(
urn.to_string(),
SerializedRequestState {
state: RequestState::from(request).to_string(),
peers: request
.peers()
.cloned()
.unwrap_or_else(std::collections::HashMap::new),
},
)
})
.collect();
Self(inner)
}
}
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@
"baseUrl": "./",
/* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
"paths": {
"ui/*": ["ui/*"]
"ui/*": ["ui/*"],
"*": ["./typings/*"]
},
/* List of root folders whose combined content represents the structure of the project at runtime. */
// "rootDirs": [],
Expand Down
8 changes: 8 additions & 0 deletions typings/svelte-json-tree/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
declare module "svelte-json-tree" {
import type { SvelteComponentTyped } from "svelte";
interface Props {
key?: string;
value: any; // eslint-disable-line @typescript-eslint/no-explicit-any
}
export default class JSONTree extends SvelteComponentTyped<Props> {}
}
2 changes: 2 additions & 0 deletions ui/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import Project from "./Screen/Project.svelte";
import Settings from "./Screen/Settings.svelte";
import UserProfile from "./Screen/UserProfile.svelte";
import NetworkDiagnostics from "./Screen/NetworkDiagnostics.svelte";

const routes = {
"/": Blank,
Expand All @@ -44,6 +45,7 @@
"/user/:urn": UserProfile,
"/user/:urn/*": UserProfile,
"/design-system-guide": DesignSystemGuide,
"/network-diagnostics/*": NetworkDiagnostics,
"*": NotFound,
};

Expand Down
10 changes: 9 additions & 1 deletion ui/DesignSystem/Component/ConnectionStatusIndicator.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
import Syncing from "./ConnectionStatusIndicator/Syncing.svelte";
import Offline from "./ConnectionStatusIndicator/Offline.svelte";

const connectedPeerCount = (peers: { [peerId: string]: string[] }) => {
const count = Object.keys(peers).length;
peerCount(count);
};

const peerCount = (count: number) => {
if (count === 1) {
return "1 peer";
Expand All @@ -31,7 +36,10 @@

<div>
{#if $status.type === StatusType.Online}
<Tooltip value={`You’re connected to ${peerCount($status.connected)}`}>
<Tooltip
value={`You’re connected to ${connectedPeerCount(
$status.connectedPeers
)}`}>
<div class="item indicator" data-cy="connection-status-online">
<Icon.Network />
</div>
Expand Down
3 changes: 3 additions & 0 deletions ui/Hotkeys.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@
case hotkeys.ShortcutKey.NewProjects:
toggleModal(ModalNewProject);
break;
case hotkeys.ShortcutKey.NetworkDiagnostics:
toggle(path.networkDiagnosticsConnectedPeers());
break;
}
};
</script>
Expand Down
61 changes: 61 additions & 0 deletions ui/Screen/NetworkDiagnostics.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<script lang="typescript">
import Router from "svelte-spa-router";

import { status as store } from "ui/src/localPeer";
import * as path from "ui/src/path";

import ActionBar from "ui/DesignSystem/Component/ActionBar.svelte";
import Header from "ui/DesignSystem/Component/Header.svelte";
import HorizontalMenu from "ui/DesignSystem/Component/HorizontalMenu.svelte";
import SidebarLayout from "ui/DesignSystem/Component/SidebarLayout.svelte";

import IconNetwork from "ui/DesignSystem/Primitive/Icon/Network.svelte";
import IconRoad from "ui/DesignSystem/Primitive/Icon/Road.svelte";

import ConnectedPeers from "./NetworkDiagnostics/ConnectedPeers.svelte";
import WaitingRoom from "./NetworkDiagnostics/WaitingRoom.svelte";

const screenRoutes = {
[path.networkDiagnosticsConnectedPeers()]: ConnectedPeers,
[path.networkDiagnosticsWaitingRoom()]: WaitingRoom,
};

const topbarMenuItems = [
{
icon: IconNetwork,
title: "Peers",
href: path.networkDiagnosticsConnectedPeers(),
looseActiveStateMatching: true,
},
{
icon: IconRoad,
title: "Requests",
href: path.networkDiagnosticsWaitingRoom(),
looseActiveStateMatching: true,
},
];
</script>

<style>
.title {
display: flex;
flex-direction: column;
justify-content: center;
}
</style>

<SidebarLayout>
<Header>
<div slot="left" class="title">
<h1>Status: {$store.type}</h1>
</div>
</Header>

<ActionBar>
<div slot="left">
<HorizontalMenu items={topbarMenuItems} />
</div>
</ActionBar>

<Router routes={screenRoutes} />
</SidebarLayout>
47 changes: 47 additions & 0 deletions ui/Screen/NetworkDiagnostics/ConnectedPeers.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<script lang="typescript">
import { StatusType, status } from "ui/src/localPeer";

let isOnline = false;
let connectedPeers: { [peerId: string]: string[] } = {};
$: if ($status.type === StatusType.Online) {
isOnline = true;
connectedPeers = $status.connectedPeers;
}
</script>

<style>
table {
table-layout: fixed;
width: 100%;
border-collapse: collapse;
border: 3px solid purple;
}
</style>

{#if isOnline}
<div>
<h2>Connected Peers</h2>
<table>
<thead>
<tr>
<td>Peer</td>
<td>Connections</td>
</tr>
</thead>
<tbody>
{#each Object.keys(connectedPeers).sort() as peerId}
<tr>
<td>{peerId}</td>
<td>
<ul>
{#each connectedPeers[peerId].sort() as address}
<li>{address}</li>
{/each}
</ul>
</td>
</tr>
{/each}
</tbody>
</table>
</div>
{/if}
43 changes: 43 additions & 0 deletions ui/Screen/NetworkDiagnostics/StateTable.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<script lang="typescript">
import type { RoomState } from "ui/src/waitingRoom";
import StyledCopyable from "ui/DesignSystem/Component/StyledCopyable.svelte";

export let state: RoomState;
</script>

<table>
<thead>
<tr>
<td>Urn</td>
<td>State</td>
<td>Peer States</td>
</tr>
</thead>
<tbody>
{#each Object.keys(state).sort() as urn}
<tr>
<td>
<StyledCopyable value={urn} truncate={true} expandable={false} />
</td>
<td>{state[urn].state}</td>
<td>
<table>
<tbody>
{#each Object.keys(state[urn].peers).sort() as peerId}
<tr>
<td>
<StyledCopyable
value={peerId}
truncate={true}
expandable={false} />
</td>
<td>{JSON.stringify(state[urn].peers[peerId])}</td>
</tr>
{/each}
</tbody>
</table>
</td>
</tr>
{/each}
</tbody>
</table>
Loading