Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.1.1 #55

Merged
merged 2 commits into from
Sep 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
19 changes: 10 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
FROM bufbuild/buf:latest AS buf-builder
FROM --platform=$BUILDPLATFORM bufbuild/buf:latest AS buf-builder
WORKDIR /opt/protobuf
COPY protobuf /opt/protobuf
RUN buf generate

FROM node:alpine AS node-builder
FROM --platform=$BUILDPLATFORM node:alpine AS node-builder
WORKDIR /opt
COPY webui /opt/webui
COPY --from=buf-builder /opt/protobuf /opt/protobuf
Expand All @@ -13,23 +13,24 @@ RUN cd protobuf \
&& npm install \
&& npm run build

FROM golang:alpine AS go-builder
FROM --platform=$BUILDPLATFORM golang:alpine AS go-builder
ENV CGO_ENABLED=0
ARG VERSION=untracked
ARG TARGETOS TARGETARCH
WORKDIR /opt
COPY pkg /opt/pkg
COPY cmd/server /opt/cmd/server
COPY go.mod go.sum /opt/.
COPY --from=buf-builder /opt/protobuf /opt/protobuf
COPY --from=node-builder /opt/cmd/server/dist /opt/cmd/server/dist
RUN apk --no-cache add ca-certificates \
&& go mod tidy \
&& go build -ldflags="-X github.com/AS203038/looking-glass/pkg/utils.release=${VERSION}" -o /opt/looking-glass /opt/cmd/server
&& go mod download \
&& GOOS=$TARGETOS GOARCH=$TARGETARCH go build -x -ldflags="-X github.com/AS203038/looking-glass/pkg/utils.release=${VERSION}" -o /opt/looking-glass /opt/cmd/server

FROM scratch
LABEL org.opencontainers.image.source https://github.com/AS203038/looking-glass
LABEL org.opencontainers.image.description Yet another looking glass project
LABEL org.opencontainers.image.licenses GPL-3.0-or-later
FROM scratch AS final
LABEL org.opencontainers.image.source=https://github.com/AS203038/looking-glass
LABEL org.opencontainers.image.description="Yet another looking glass project"
LABEL org.opencontainers.image.licenses=GPL-3.0-or-later
WORKDIR /
COPY --from=go-builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=go-builder /opt/looking-glass /looking-glass
Expand Down
35 changes: 19 additions & 16 deletions pkg/http/webui/webui.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,25 @@ type EnvJS struct {
}

func ConfigInjector(cfg utils.WebConfig) http.Handler {
envjson, err := json.Marshal(EnvJS{
Theme: cfg.Theme,
PageTitle: cfg.Title,
HeaderText: cfg.Header.Text,
HeaderLinks: cfg.Header.LinksString(),
HeaderLogo: cfg.Header.Logo,
FooterText: cfg.Footer.Text,
FooterLinks: cfg.Footer.LinksString(),
FooterLogo: cfg.Footer.Logo,
GrpcURL: cfg.GrpcURL,
LGVersion: utils.Version(),
SentryDSN: cfg.Sentry.DSN,
SentryEnv: cfg.Sentry.Environment,
SentrySampleRate: cfg.Sentry.SampleRate,
RtListMax: cfg.RtListMax,
})
envobj := EnvJS{
Theme: cfg.Theme,
PageTitle: cfg.Title,
HeaderText: cfg.Header.Text,
HeaderLinks: cfg.Header.LinksString(),
HeaderLogo: cfg.Header.Logo,
FooterText: cfg.Footer.Text,
FooterLinks: cfg.Footer.LinksString(),
FooterLogo: cfg.Footer.Logo,
GrpcURL: cfg.GrpcURL,
LGVersion: utils.Version(),
RtListMax: cfg.RtListMax,
}
if cfg.Sentry.Enabled {
envobj.SentryDSN = cfg.Sentry.DSN
envobj.SentryEnv = cfg.Sentry.Environment
envobj.SentrySampleRate = cfg.Sentry.SampleRate
}
envjson, err := json.Marshal(envobj)
if err != nil {
panic(err)
}
Expand Down
213 changes: 103 additions & 110 deletions webui/src/lib/components/execCommand.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
let outputs: Record<
string,
{
result: Uint8Array | undefined;
timestamp: Date | undefined;
length: number;
ready: boolean;
Expand All @@ -25,103 +24,104 @@

export let exec = (a: string, b: string) => {};

async function execCommand(
router: Pb.Router,
command: string,
parameter: string,
) {
const routerId = router.id.toString();
outputs[routerId] = {
timestamp: undefined,
length: 0,
ready: false,
pages: [],
currentPage: 0,
pageSize: 1024 * 1024 * 1, // 1MB per page
};
let res:
| Pb.PingResponse
| Pb.TracerouteResponse
| Pb.BGPRouteResponse
| Pb.BGPCommunityResponse
| Pb.BGPASPathResponse;
try {
switch (command) {
case "ping":
res = await LookingGlassClient().ping(<Pb.PingRequest>{
routerId: router.id,
target: parameter,
});
break;
case "traceroute":
res = await LookingGlassClient().traceroute(<Pb.TracerouteRequest>{
routerId: router.id,
target: parameter,
});
break;
case "bgp_route":
res = await LookingGlassClient().bGPRoute(<Pb.BGPRouteRequest>{
routerId: router.id,
target: parameter,
});
break;
case "bgp_community":
res = await LookingGlassClient().bGPCommunity(<
Pb.BGPCommunityRequest
>{
routerId: router.id,
community: <Pb.BGPCommunity>{
asn: parseInt(parameter.split(":")[0]),
value: parseInt(parameter.split(":")[1]),
},
});
break;
case "bgp_aspath_regex":
res = await LookingGlassClient().bGPASPath(<Pb.BGPASPathRequest>{
routerId: router.id,
pattern: parameter,
});
break;
default:
console.log("Unknown command");
return;
}
} catch (e) {
outputs[routerId].result = new TextEncoder().encode(
`Error: ${e.message}`,
);
outputs[routerId].timestamp = new Date();
outputs[routerId].ready = true;
console.error(e); // Log the error potentially for sentry
return;
}
outputs[routerId].length = res.result.length;
// Split result into pages
for (let i = 0; i < res.result.length; ) {
let end = i + outputs[routerId].pageSize;
if (end < res.result.length) {
// Find the next newline character after the pageSize
while (end < res.result.length && res.result[end] !== 10) {
// 10 is the ASCII code for newline
end++;
}
end++; // Include the newline character in the chunk
}
outputs[routerId].pages.push(res.result.slice(i, end));
i = end;
}
outputs[routerId].timestamp = new Date(
parseInt(res.timestamp.seconds.toString()) * 1000,
);
outputs[routerId].ready = true;
}

async function _exec(command: string, parameter: string) {
fire = true;
outputs = {};
_command = command;
_parameter = parameter;
for (let router of routers) {
const routerId = router.id.toString();
outputs[routerId] = {
result: undefined,
timestamp: undefined,
download: false,
blob: undefined,
length: 0,
ready: false,
pages: [],
currentPage: 0,
pageSize: 1024 * 1024 * 1, // 1MB per page
};
let res:
| Pb.PingResponse
| Pb.TracerouteResponse
| Pb.BGPRouteResponse
| Pb.BGPCommunityResponse
| Pb.BGPASPathResponse;
try {
switch (command) {
case "ping":
res = await LookingGlassClient().ping(<Pb.PingRequest>{
routerId: router.id,
target: parameter,
});
break;
case "traceroute":
res = await LookingGlassClient().traceroute(<Pb.TracerouteRequest>{
routerId: router.id,
target: parameter,
});
break;
case "bgp_route":
res = await LookingGlassClient().bGPRoute(<Pb.BGPRouteRequest>{
routerId: router.id,
target: parameter,
});
break;
case "bgp_community":
res = await LookingGlassClient().bGPCommunity(<
Pb.BGPCommunityRequest
>{
routerId: router.id,
community: <Pb.BGPCommunity>{
asn: parseInt(parameter.split(":")[0]),
value: parseInt(parameter.split(":")[1]),
},
});
break;
case "bgp_aspath_regex":
res = await LookingGlassClient().bGPASPath(<Pb.BGPASPathRequest>{
routerId: router.id,
pattern: parameter,
});
break;
default:
console.log("Unknown command");
return;
}
} catch (e) {
outputs[routerId].result = new TextEncoder().encode(
`Error: ${e.message}`,
);
outputs[routerId].timestamp = new Date();
outputs[routerId].ready = true;
continue;
}
outputs[routerId].length = res.result.length;
if (res.result.length > outputs[routerId].pageSize) {
// Split result into pages
for (let i = 0; i < res.result.length; ) {
let end = i + outputs[routerId].pageSize;
if (end < res.result.length) {
// Find the next newline character after the pageSize
while (end < res.result.length && res.result[end] !== 10) {
// 10 is the ASCII code for newline
end++;
}
end++; // Include the newline character in the chunk
}
outputs[routerId].pages.push(res.result.slice(i, end));
i = end;
}
} else {
outputs[routerId].result = res.result;
}
// }
outputs[routerId].timestamp = new Date(
parseInt(res.timestamp.seconds.toString()) * 1000,
);
outputs[routerId].ready = true;
execCommand(router, command, parameter);
}
}
$: exec = _exec;
Expand Down Expand Up @@ -152,7 +152,7 @@
<div class="flex flex-wrap justify-evenly gap-4 mt-2">
{#each routers as router}
{#if outputs[router.id.toString()] !== undefined}
<div transition:fade|global class="card text-left p-4">
<div transition:fade|global class="card text-left p-4 max-w-screen">
<header class="card-header">
<p class="font-medium">Router: {router.name}</p>
<p class="capitalize">Location: {router.location}</p>
Expand All @@ -161,27 +161,20 @@
{#if outputs[router.id.toString()].ready === false}
<div
in:fade|global
class="text-center flex flex-col items-center max-h-80 h-max max-w-3xl w-max"
class="text-center flex flex-col items-center max-h-80 h-max max-w-3xl min-w-3xl w-full"
>
<ProgressRadial />
</div>
{:else}
{#if outputs[router.id.toString()]?.pages.length === 0}
<pre
in:fade|global
class="pre text-left max-h-80 h-max max-w-3xl w-max overflow-scroll"
data-clipboard={router.id.toString()}>{new TextDecoder().decode(
outputs[router.id.toString()].result,
)}</pre>
{:else}
<pre
in:fade|global
class="pre text-left max-h-80 h-max max-w-3xl w-max overflow-scroll"
data-clipboard={router.id.toString()}>{new TextDecoder().decode(
outputs[router.id.toString()].pages[
outputs[router.id.toString()].currentPage
],
)}</pre>
<pre
in:fade|global
class="pre text-left max-h-80 h-max max-w-3xl min-w-3xl w-full overflow-scroll"
data-clipboard={router.id.toString()}>{new TextDecoder().decode(
outputs[router.id.toString()].pages[
outputs[router.id.toString()].currentPage
],
)}</pre>
{#if outputs[router.id.toString()].pages.length > 1}
<div class="flex justify-between mt-2">
<button
class="btn variant-filled-primary"
Expand Down
Loading