Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit f46ff368 authored by Simon Chan's avatar Simon Chan
Browse files

feat(demo): packet logger done

fix #397
parent 5f1fa119
Loading
Loading
Loading
Loading
+102 −6
Original line number Diff line number Diff line
import { makeStyles } from "@griffel/react";
import { makeStyles, mergeClasses } from "@griffel/react";
import { ReactNode, useMemo } from "react";
import { withDisplayName } from "../utils";

const useClasses = makeStyles({
    root: {
        width: '100%',
        height: '100%',
        overflowY: 'auto',
    },
    flex: {

        display: 'flex',
    },
    cell: {
        fontFamily: '"Cascadia Code", Consolas, monospace',
    },
    lineNumber: {
        textAlign: 'right',
    },
    hex: {
        marginLeft: '40px',
    },
});

export interface HexViewer {
const PRINTABLE_CHARACTERS: [number, number][] = [
    [33, 126],
    [161, 172],
    [174, 255],
];

export function isPrintableCharacter(code: number) {
    return PRINTABLE_CHARACTERS.some(
        ([start, end]) =>
            code >= start &&
            code <= end
    );
}

export function toCharacter(code: number) {
    if (isPrintableCharacter(code))
        return String.fromCharCode(code);
    return '.';
}

export function toText(data: Uint8Array) {
    let result = '';
    for (const code of data) {
        result += toCharacter(code);
    }
    return result;
}

const PER_ROW = 16;

export interface HexViewerProps {
    className?: string;
    data: Uint8Array;
}

export const HexViewer = withDisplayName('HexViewer')(({

}) => {
    className,
    data
}: HexViewerProps) => {
    const classes = useClasses();

    // Because ADB packets are usually small,
    // so don't add virtualization now.

    return (
    const children = useMemo(() => {
        const lineNumbers: ReactNode[] = [];
        const hexRows: ReactNode[] = [];
        const textRows: ReactNode[] = [];
        for (let i = 0; i < data.length; i += PER_ROW) {
            lineNumbers.push(
                <div>
                    {i.toString(16)}
                </div>
            );

            let hex = '';
            for (let j = i; j < i + PER_ROW && j < data.length; j++) {
                hex += data[j].toString(16).padStart(2, '0') + ' ';
            }
            hexRows.push(
                <div>
                    {hex}
                </div>
            );

            textRows.push(
                <div>
                    {toText(data.slice(i, i + PER_ROW))}
                </div>
            );
        }

        return {
            lineNumbers,
            hexRows,
            textRows,
        };
    }, [data]);

    return (
        <div className={mergeClasses(classes.root, className)}>
            <div className={classes.flex}>
                <div className={mergeClasses(classes.cell, classes.lineNumber)}>
                    {children.lineNumbers}
                </div>
                <div className={mergeClasses(classes.cell, classes.hex)}>
                    {children.hexRows}
                </div>
                <div className={mergeClasses(classes.cell, classes.hex)}>
                    {children.textRows}
                </div>
            </div>
        </div>
    );
});
+1 −0
Original line number Diff line number Diff line
@@ -5,5 +5,6 @@ export * from './device-view';
export * from './error-dialog';
export * from './external-link';
export * from './grid';
export * from './hex-viewer';
export * from './log-view';
export * from './resize-observer';
+72 −72
Original line number Diff line number Diff line
import { ICommandBarItemProps, Stack, StackItem } from "@fluentui/react";
import { makeStyles, mergeClasses, shorthands } from "@griffel/react";
import { AdbCommand, decodeUtf8 } from "@yume-chan/adb";
import { makeAutoObservable } from "mobx";
import { autorun, makeAutoObservable, observable, runInAction } from "mobx";
import { observer } from "mobx-react-lite";
import { NextPage } from "next";
import Head from "next/head";
import { useMemo, useState } from "react";
import { CommandBar, Grid, GridCellProps, GridColumn, GridHeaderProps, GridRowProps } from "../components";
import { useMemo } from "react";
import { CommandBar, Grid, GridCellProps, GridColumn, GridHeaderProps, GridRowProps, HexViewer, toText } from "../components";
import { globalState, PacketLogItem } from "../state";
import { Icons, RouteStackProps, useCallbackRef, withDisplayName } from "../utils";

@@ -19,40 +19,12 @@ const ADB_COMMAND_NAME = {
    [AdbCommand.Write]: 'WRTE',
};

interface Column<T> extends GridColumn {
interface Column extends GridColumn {
    title: string;
}

const LINE_HEIGHT = 32;

const PRINTABLE_CHARACTERS: [number, number][] = [
    [33, 126],
    [161, 172],
    [174, 255],
];

function isPrintableCharacter(code: number) {
    return PRINTABLE_CHARACTERS.some(
        ([start, end]) =>
            code >= start &&
            code <= end
    );
}

function toCharacter(code: number) {
    if (isPrintableCharacter(code))
        return String.fromCharCode(code);
    return '.';
}

function toText(data: Uint8Array) {
    let result = '';
    for (const code of data) {
        result += toCharacter(code);
    }
    return result;
}

const state = new class {
    get commandBarItems(): ICommandBarItemProps[] {
        return [
@@ -66,12 +38,28 @@ const state = new class {
        ];
    }

    selectedPacket: PacketLogItem | undefined = undefined;

    constructor() {
        makeAutoObservable(this);
        makeAutoObservable(
            this,
            {
                selectedPacket: observable.ref,
            }
        );

        autorun(() => {
            if (globalState.logs.length === 0) {
                this.selectedPacket = undefined;
            }
        });
    }
};

const useClasses = makeStyles({
    grow: {
        height: 0,
    },
    grid: {
        height: '100%',
    },
@@ -95,12 +83,16 @@ const useClasses = makeStyles({
        cursor: 'default',
        ...shorthands.overflow('hidden'),
    },
    hexViewer: {
        ...shorthands.padding('12px'),
        ...shorthands.borderTop('1px', 'solid', 'rgb(243, 242, 241)'),
    },
});

const PacketLog: NextPage = () => {
    const classes = useClasses();

    const columns: Column<PacketLogItem>[] = useMemo(() => [
    const columns: Column[] = useMemo(() => [
        {
            key: 'direction',
            title: 'Direction',
@@ -207,24 +199,32 @@ const PacketLog: NextPage = () => {
        },
    ], [classes.code]);

    const [selectedRowIndex, setSelectedRowIndex] = useState(-1);

    const Header = useMemo(() => withDisplayName('Header')(({ className, columnIndex, ...rest }: GridHeaderProps) => {
    const Header = useMemo(
        () => withDisplayName('Header')(({
            className,
            columnIndex,
            ...rest
        }: GridHeaderProps) => {
            return (
                <div className={mergeClasses(className, classes.header)} {...rest}>
                    {columns[columnIndex].title}
                </div>
            );
    }), [classes.header, columns]);
        }),
        [classes.header, columns]
    );

    const Row = useMemo(() => withDisplayName('Row')(({
    const Row = useMemo(
        () => observer(function Row({
            className,
            rowIndex,
            ...rest
    }: GridRowProps) => {
        }: GridRowProps) {
            /* eslint-disable-next-line */
            const handleClick = useCallbackRef(() => {
            setSelectedRowIndex(rowIndex);
                runInAction(() => {
                    state.selectedPacket = globalState.logs[rowIndex];
                });
            });

            return (
@@ -232,13 +232,15 @@ const PacketLog: NextPage = () => {
                    className={mergeClasses(
                        className,
                        classes.row,
                    selectedRowIndex === rowIndex && classes.selected
                        state.selectedPacket === globalState.logs[rowIndex] && classes.selected
                    )}
                    onClick={handleClick}
                    {...rest}
                />
            );
    }), [classes, selectedRowIndex]);
        }),
        [classes]
    );

    return (
        <Stack {...RouteStackProps} tokens={{}}>
@@ -248,7 +250,7 @@ const PacketLog: NextPage = () => {

            <CommandBar items={state.commandBarItems} />

            <StackItem basis={0} grow>
            <StackItem className={classes.grow} grow>
                <Grid
                    className={classes.grid}
                    rowCount={globalState.logs.length}
@@ -259,13 +261,11 @@ const PacketLog: NextPage = () => {
                />
            </StackItem>

            <StackItem grow>
                {selectedRowIndex !== -1 && (
                    <div>

                    </div>
                )}
            {state.selectedPacket && state.selectedPacket.payload.length > 0 && (
                <StackItem className={classes.grow} grow>
                    <HexViewer className={classes.hexViewer} data={state.selectedPacket.payload} />
                </StackItem>
            )}
        </Stack>
    );
};