-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #26 from erigontech/peersimpl
save
- Loading branch information
Showing
7 changed files
with
2,645 additions
and
2,028 deletions.
There are no files selected for viewing
99 changes: 99 additions & 0 deletions
99
src/app/components/SyncStages/TorrentPeersDetailsPopup.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { useSelector } from "react-redux"; | ||
import { useEffect } from "react"; | ||
import { selectTorrrentPeersForNode } from "../../store/syncStagesSlice"; | ||
import CloseIcon from "@mui/icons-material/Close"; | ||
import { TorrentPeersTable } from "./TorrentPeersTable"; | ||
|
||
interface TorrentPeersDetailsPopupProps { | ||
onClose: () => void; | ||
} | ||
|
||
export const TorrentPeersDetailsPopup = ({ onClose }: TorrentPeersDetailsPopupProps) => { | ||
const peers = useSelector(selectTorrrentPeersForNode); | ||
|
||
const handleKeyPress = (event: KeyboardEvent) => { | ||
if (event.key === "Escape") { | ||
onClose(); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
window.addEventListener("keydown", handleKeyPress); | ||
|
||
return () => { | ||
window.removeEventListener("keydown", handleKeyPress); | ||
}; | ||
}, []); | ||
|
||
const renderHeader = () => { | ||
return ( | ||
<div className="flex flex-row w-full pt-10 pr-10 pl-10"> | ||
<div className="flex-[1]"></div> | ||
<div className="flex flex-[2] justify-center"> | ||
<h3 className="text-3xl font-semibold">Peers list</h3> | ||
</div> | ||
<div className="flex flex-[1] justify-end"> | ||
<CloseIcon | ||
onClick={() => onClose()} | ||
className="cursor-pointer" | ||
/> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
const bytesToString = (bts: number[]): string => { | ||
//let s = bytes.map((byte) => String.fromCharCode(byte)).join(""); | ||
const bytes = new Uint8Array(bts); | ||
let res = toString(bytes); | ||
return res; | ||
}; | ||
|
||
function toString(id: Uint8Array): string { | ||
// Equivalent of the Go code checking `me[0] == '-' && me[7] == '-'` | ||
if (id[0] === 45 && id[7] === 45) { | ||
// 45 is the ASCII code for '-' | ||
//return byteArrayToString(id.slice(0, 8)) + byteArrayToHex(id.slice(8)); | ||
return byteArrayToHex(id.slice(8)); | ||
} | ||
|
||
// Hex encoding of the entire array if no condition is met | ||
return byteArrayToHex(id); | ||
} | ||
|
||
// Helper function to convert byte array to string | ||
function byteArrayToString(bytes: Uint8Array): string { | ||
return new TextDecoder().decode(bytes); | ||
} | ||
|
||
// Helper function to convert byte array to hex string | ||
function byteArrayToHex(bytes: Uint8Array): string { | ||
return Array.from(bytes) | ||
.map((b) => b.toString(16).padStart(2, "0")) | ||
.join(""); | ||
} | ||
|
||
return ( | ||
<> | ||
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto inset-0 z-50 outline-none focus:outline-none absolute bg-black/[.4]"> | ||
<div className="relative w-auto my-6 mx-auto max-w-[100vw]"> | ||
{/*content*/} | ||
<div className="border-0 rounded-lg shadow-lg relative flex flex-col w-fit bg-white outline-none focus:outline-none items-center"> | ||
{/*header*/} | ||
{renderHeader()} | ||
{/*body*/} | ||
<div className="flex flex-col relative p-6 flex-auto justify-start items-center h-[75vh] overflow-scroll"> | ||
<TorrentPeersTable | ||
peers={peers} | ||
peerSelected={false} | ||
onPeerClicked={() => {}} | ||
/> | ||
</div> | ||
{/*footer*/} | ||
</div> | ||
</div> | ||
</div> | ||
<div className="opacity-25 inset-0 z-40 bg-black"></div> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
import { useState } from "react"; | ||
import { multipleBytes } from "../../../helpers/converters"; | ||
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown"; | ||
import ArrowDropUpIcon from "@mui/icons-material/ArrowDropUp"; | ||
import SortIcon from "@mui/icons-material/Sort"; | ||
import { SegmentPeer } from "../../store/syncStagesSlice"; | ||
|
||
enum SortColumn { | ||
Url = "Url", | ||
DlRate = "DlRate", | ||
Address = "Address", | ||
ID = "ID", | ||
PiecesCount = "PiecesCount", | ||
TorrentName = "TorrentName" | ||
} | ||
|
||
interface SortState { | ||
column: SortColumn; | ||
descending: boolean; | ||
} | ||
|
||
export interface TorrentPeersTableProps { | ||
peers: SegmentPeer[]; | ||
peerSelected: boolean; | ||
onPeerClicked: (segment: SegmentPeer) => void; | ||
} | ||
|
||
export const TorrentPeersTable = ({ peers, peerSelected, onPeerClicked }: TorrentPeersTableProps) => { | ||
const [visibleSegments, setVisibleSegments] = useState<SegmentPeer[]>(peers); | ||
|
||
const [currentSortState, setCurrentSortState] = useState<SortState>({ | ||
column: SortColumn.Url, | ||
descending: true | ||
}); | ||
|
||
const sortSegments = (seg: SegmentPeer[], sotOpt: SortState): void => { | ||
console.log("sortSegments", seg[0]); | ||
let tosort = [...seg]; | ||
let sortedSegments = tosort.sort((a, b) => { | ||
if (sotOpt.column === SortColumn.Url) { | ||
return compareStrings(a.url, b.url, sotOpt.descending); | ||
} else if (sotOpt.column === SortColumn.DlRate) { | ||
return compareNumbers(a.downloadRate, b.downloadRate, sotOpt.descending); | ||
} else if (sotOpt.column === SortColumn.PiecesCount) { | ||
return compareNumbers(a.piecesCount, b.piecesCount, sotOpt.descending); | ||
} else if (sotOpt.column === SortColumn.Address) { | ||
return compareStrings(a.remoteAddr, b.remoteAddr, sotOpt.descending); | ||
} else if (sotOpt.column === SortColumn.ID) { | ||
return compareStrings(bytesToString(a.peerId), bytesToString(b.peerId), sotOpt.descending); | ||
} else { | ||
return compareStrings(a.torrentName, b.torrentName, sotOpt.descending); | ||
} | ||
}); | ||
|
||
console.log("sortedSegments", sortedSegments[0]); | ||
|
||
setCurrentSortState(sotOpt); | ||
setVisibleSegments(sortedSegments); | ||
}; | ||
|
||
const compareStrings = (a: string, b: string, desc: boolean) => { | ||
if (desc) { | ||
return b.localeCompare(a); | ||
} else { | ||
return a.localeCompare(b); | ||
} | ||
}; | ||
|
||
const compareNumbers = (a: number, b: number, desc: boolean) => { | ||
if (desc) { | ||
return b - a; | ||
} else { | ||
return a - b; | ||
} | ||
}; | ||
|
||
const getArrowIcon = (column: SortColumn) => { | ||
if (currentSortState.column !== column) { | ||
return <SortIcon className="ml-2" />; | ||
} else { | ||
if (currentSortState.descending) { | ||
return <ArrowDropDownIcon />; | ||
} else { | ||
return <ArrowDropUpIcon />; | ||
} | ||
} | ||
}; | ||
|
||
const bytesToString = (bts: number[]): string => { | ||
//let s = bytes.map((byte) => String.fromCharCode(byte)).join(""); | ||
const bytes = new Uint8Array(bts); | ||
let res = toString(bytes); | ||
return res; | ||
}; | ||
|
||
function toString(id: Uint8Array): string { | ||
// Equivalent of the Go code checking `me[0] == '-' && me[7] == '-'` | ||
if (id[0] === 45 && id[7] === 45) { | ||
// 45 is the ASCII code for '-' | ||
//return byteArrayToString(id.slice(0, 8)) + byteArrayToHex(id.slice(8)); | ||
return byteArrayToHex(id.slice(8)); | ||
} | ||
|
||
// Hex encoding of the entire array if no condition is met | ||
return byteArrayToHex(id); | ||
} | ||
|
||
// Helper function to convert byte array to string | ||
function byteArrayToString(bytes: Uint8Array): string { | ||
return new TextDecoder().decode(bytes); | ||
} | ||
|
||
// Helper function to convert byte array to hex string | ||
function byteArrayToHex(bytes: Uint8Array): string { | ||
return Array.from(bytes) | ||
.map((b) => b.toString(16).padStart(2, "0")) | ||
.join(""); | ||
} | ||
|
||
return ( | ||
<div | ||
className="w-full h-[95%]" | ||
style={{ overflowY: !peerSelected ? "scroll" : "hidden" }} | ||
> | ||
<table className="table-fixed text-left"> | ||
<thead> | ||
<tr className="border-b"> | ||
<th | ||
className="px-4 py-2 cursor-pointer" | ||
onClick={() => { | ||
sortSegments(visibleSegments, { | ||
column: SortColumn.Url, | ||
descending: !currentSortState.descending | ||
}); | ||
}} | ||
> | ||
<div className="flex flex-row"> | ||
URL | ||
{getArrowIcon(SortColumn.Url)} | ||
</div> | ||
</th> | ||
<th | ||
className="px-4 py-2 cursor-pointer" | ||
onClick={() => { | ||
sortSegments(visibleSegments, { | ||
column: SortColumn.DlRate, | ||
descending: !currentSortState.descending | ||
}); | ||
}} | ||
> | ||
<div className="flex flex-row"> | ||
Download Rate | ||
{getArrowIcon(SortColumn.DlRate)} | ||
</div> | ||
</th> | ||
<th | ||
className="px-4 py-2 cursor-pointer" | ||
onClick={() => { | ||
sortSegments(visibleSegments, { | ||
column: SortColumn.Address, | ||
descending: !currentSortState.descending | ||
}); | ||
}} | ||
> | ||
<div className="flex flex-row"> | ||
Remote Address | ||
{getArrowIcon(SortColumn.Address)} | ||
</div> | ||
</th> | ||
<th | ||
className="px-4 py-2 cursor-pointer" | ||
onClick={() => { | ||
sortSegments(visibleSegments, { | ||
column: SortColumn.ID, | ||
descending: !currentSortState.descending | ||
}); | ||
}} | ||
> | ||
<div className="flex flex-row"> | ||
ID | ||
{getArrowIcon(SortColumn.ID)} | ||
</div> | ||
</th> | ||
<th | ||
className="px-4 py-2 cursor-pointer" | ||
onClick={() => { | ||
sortSegments(visibleSegments, { | ||
column: SortColumn.PiecesCount, | ||
descending: !currentSortState.descending | ||
}); | ||
}} | ||
> | ||
<div className="flex flex-row"> | ||
Pieces Count | ||
{getArrowIcon(SortColumn.PiecesCount)} | ||
</div> | ||
</th> | ||
<th | ||
className="px-4 py-2 cursor-pointer" | ||
onClick={() => { | ||
sortSegments(visibleSegments, { | ||
column: SortColumn.TorrentName, | ||
descending: !currentSortState.descending | ||
}); | ||
}} | ||
> | ||
<div className="flex flex-row"> | ||
Torrent Name | ||
{getArrowIcon(SortColumn.TorrentName)} | ||
</div> | ||
</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{visibleSegments.map((peer) => { | ||
return ( | ||
<tr | ||
key={uniqueId()} | ||
className="border-b" | ||
> | ||
<td className="px-4 py-2">{peer.url}</td> | ||
<td className="px-4 py-2">{multipleBytes(peer.downloadRate)}</td> | ||
<td className="px-4 py-2">{peer.remoteAddr}</td> | ||
<td className="px-4 py-2">{bytesToString(peer.peerId)}</td> | ||
<td className="px-4 py-2">{peer.piecesCount}</td> | ||
<td className="px-4 py-2">{peer.torrentName}</td> | ||
</tr> | ||
); | ||
})} | ||
</tbody> | ||
</table> | ||
</div> | ||
); | ||
|
||
function uniqueId() { | ||
return Math.random().toString(36).substr(2, 9); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.