Skip to content
Open
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
565 changes: 565 additions & 0 deletions documentation/docs/library_services/presence.mdx

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions documentation/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ const sidebars = {
"library_services/mailgun",
"library_services/oauth_token_manager",
"library_services/ordered_map",
"library_services/presence",
"library_services/pubsub",
"library_services/queue",
"library_services/sorted_map",
Expand Down
5 changes: 3 additions & 2 deletions reboot/std/react/presence/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,9 @@ const MouseArrow: FC<{ id: string; arrow: ReactNode }> = ({ id, arrow }) => {

return (
<div
className="absolute text-black"
className="presence-mouse-arrow"
style={{
position: "absolute",
top: response.top,
left: response.left,
}}
Expand All @@ -134,7 +135,7 @@ export const MouseTracker: FC<{
arrow: ReactNode;
className?: string;
style?: React.CSSProperties;
children: ReactNode;
children?: ReactNode;
}> = ({ arrow, className, style, children }) => {
const { subscriberId, subscriberIds } = usePresenceContext();

Expand Down
2 changes: 1 addition & 1 deletion tests/reboot/std/collections/queue/v1/queue_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from reboot.aio.tests import Reboot
from reboot.protobuf import as_int, as_str, from_int, from_str, pack, unpack

# Import used in Queue documentation, so we want to keep them
# Import used in Queue documentation, so we want to keep them separate.
# isort: off
from reboot.std.collections.queue.v1.queue import Queue
from reboot.std.item.v1.item import Item
Expand Down
3 changes: 3 additions & 0 deletions tests/reboot/std/presence/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ ts_project(
name = "presence_tests_ts",
srcs = [
"presence_tests.ts",
"subscriber_connect.ts",
":package.json",
],
declaration = True,
Expand All @@ -33,6 +34,8 @@ ts_project(
"//:node_modules/@reboot-dev/reboot-api",
"//:node_modules/@reboot-dev/reboot-std",
"//:node_modules/@types/node",
# Required to get uuid package.
"//tests/reboot:greeter_js_reboot",
],
)

Expand Down
12 changes: 9 additions & 3 deletions tests/reboot/std/presence/presence_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@
from reboot.aio.external import ExternalContext
from reboot.aio.memoize import MemoizeServicer
from reboot.aio.tests import Reboot

# Import used in Presence documentation, so we want to keep them separate.
# isort: off
from reboot.std.presence.v1.presence import (
ListResponse,
MousePosition,
PositionResponse,
Presence,
StatusResponse,
Subscriber,
)
# isort: on
from reboot.std.presence.v1.presence import (
ListResponse,
PositionResponse,
StatusResponse,
presence_library,
)
from typing import Optional
Expand Down
83 changes: 82 additions & 1 deletion tests/reboot/std/presence/presence_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ import {
TokenVerifier,
allow,
} from "@reboot-dev/reboot";
import { fork } from "child_process";
import { errors_pb } from "@reboot-dev/reboot-api";
import { MousePosition } from "@reboot-dev/reboot-std/presence/mouse_tracker/v1";
import { Subscriber } from "@reboot-dev/reboot-std/presence/subscriber/v1";
import { Presence, presenceLibrary } from "@reboot-dev/reboot-std/presence/v1";
import { Presence } from "@reboot-dev/reboot-std/presence/v1";
// eslint-disable-next-line
import { presenceLibrary } from "@reboot-dev/reboot-std/presence/v1";
import { strict as assert } from "node:assert";
import { test } from "node:test";
import * as uuid from "uuid";

class EmptyTokenVerifier extends TokenVerifier {
async verifyToken(
Expand Down Expand Up @@ -169,4 +173,81 @@ test("Use Presence Servicers", async (t) => {
});
}
);

await t.test("Subscriber connection", async (t) => {
await rbt.up(
new Application({
libraries: [presenceLibrary()],
tokenVerifier: new EmptyTokenVerifier(),
}),
{
// needed so URL starts with http:
localEnvoy: true,
}
);

let context = rbt.createExternalContext("test-connect");
let subscriberRef = Subscriber.ref("connect-test-subscriber");

await subscriberRef.idempotently().create(context);
let nonce = uuid.v4();

// Connect the subscriber. The following would work if we could cancel
// the promise/RPC so the test could end. However, because we can't, we use
// a subprocess instead. Left here to grab for documentation.

// let connectFailed = false;
// const promise = subscriberRef
// .connect(context, { nonce })
// .catch((_) => {
// connectFailed = true;
// });

const subprocess = fork(
"./tests/reboot/std/presence/subscriber_connect.js",
[rbt.url(), subscriberRef.stateId, nonce]
);

let attempt = 0;
while (true) {
try {
await subscriberRef
.idempotently(`attempt-${attempt}`)
.toggle(context, { nonce });
} catch (e) {
if (
e instanceof Subscriber.ToggleAborted &&
e.error instanceof errors_pb.NotFound
) {
attempt++;
continue;
} else {
break;
}
}

await Presence.ref("connect-test").subscribe(context, {
subscriberId: subscriberRef.stateId,
});
break;
}

let { present } = await subscriberRef.status(context);
assert(present);

// Tell the child process it can exit.
subprocess.send("");

await new Promise<void>((resolve, reject) => {
subprocess.on("exit", (code, signal) => {
if (code === 0) {
resolve();
} else if (signal === null) {
reject(new Error(`Child exited with code ${code}`));
} else {
reject(new Error(`Child exited with signal ${signal}`));
}
});
});
});
});
22 changes: 22 additions & 0 deletions tests/reboot/std/presence/subscriber_connect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ExternalContext } from "@reboot-dev/reboot";
import { Subscriber } from "@reboot-dev/reboot-std/presence/subscriber/v1";

const args = process.argv.slice(2);
const url = args[0];
const subscriberId = args[1];
const nonce = args[2];

const context = new ExternalContext({ name: "subscriber-connect", url });
const subscriber = Subscriber.ref(subscriberId);

subscriber.connect(context, { nonce });

await new Promise<void>((resolve) => {
process.once("message", () => {
resolve();
});
});

// Need to explicitly exit because the call to `testLongRunningWriter`
// should still be outstanding.
process.exit(0);
Loading