From 68aa7e00adacd2d28ec4ab1d93b5d1ca9e51092b Mon Sep 17 00:00:00 2001 From: Ben Bolte Date: Thu, 7 Nov 2024 16:09:31 -0800 Subject: [PATCH] teleop webrtc relay (#531) * teleop webrtc relay * stuff * refactor a bunch of stuff * wip * asdf * auto rotation * auto rotation * update teleop * webrtc version * add * fix lint * move more stuff around * update api * update types + fix tests * missed a spot --- frontend/src/components/auth/LoginForm.tsx | 9 +- frontend/src/components/auth/SignupForm.tsx | 2 +- .../src/components/auth/SignupWithEmail.tsx | 11 +- .../src/components/files/URDFRenderer.tsx | 88 +++- frontend/src/components/pages/EmailSignup.tsx | 4 +- frontend/src/components/pages/Logout.tsx | 2 +- .../terminal/TerminalRobotModel.tsx | 1 + frontend/src/gen/api.ts | 432 +++++++++++------- store/app/crud/base.py | 29 +- store/app/crud/teleop.py | 29 ++ store/app/db.py | 2 + store/app/main.py | 106 +---- store/app/model.py | 32 +- store/app/routers/artifacts.py | 5 +- store/app/routers/auth/__init__.py | 15 + store/app/routers/auth/api.py | 19 + .../{authenticate.py => auth/email.py} | 119 ++--- store/app/routers/auth/github.py | 6 +- store/app/routers/auth/google.py | 6 +- store/app/routers/email.py | 68 --- store/app/routers/kernel_images.py | 2 +- store/app/routers/keys.py | 2 +- store/app/routers/listings.py | 2 +- store/app/routers/onshape.py | 2 +- store/app/routers/orders.py | 11 +- store/app/routers/robots.py | 2 +- store/app/routers/stripe.py | 2 +- store/app/routers/teleop/__init__.py | 9 + store/app/routers/teleop/webrtc.py | 77 ++++ store/app/routers/users.py | 94 +--- store/app/security/__init__.py | 0 store/app/security/requests.py | 45 ++ store/app/security/user.py | 55 +++ store/app/templates/oauth2_redirect.html | 73 +++ tests/test_users.py | 4 +- 35 files changed, 844 insertions(+), 521 deletions(-) create mode 100644 store/app/crud/teleop.py create mode 100644 store/app/routers/auth/api.py rename store/app/routers/{authenticate.py => auth/email.py} (56%) delete mode 100644 store/app/routers/email.py create mode 100644 store/app/routers/teleop/__init__.py create mode 100644 store/app/routers/teleop/webrtc.py create mode 100644 store/app/security/__init__.py create mode 100644 store/app/security/requests.py create mode 100644 store/app/security/user.py create mode 100644 store/app/templates/oauth2_redirect.html diff --git a/frontend/src/components/auth/LoginForm.tsx b/frontend/src/components/auth/LoginForm.tsx index ddadf989..a3b238bc 100644 --- a/frontend/src/components/auth/LoginForm.tsx +++ b/frontend/src/components/auth/LoginForm.tsx @@ -23,9 +23,12 @@ const LoginForm = () => { const onSubmit: SubmitHandler = async (data: LoginType) => { try { - const { data: response, error } = await auth.client.POST("/auth/login", { - body: data, - }); + const { data: response, error } = await auth.client.POST( + "/auth/email/login", + { + body: data, + }, + ); if (error) { addErrorAlert(error); diff --git a/frontend/src/components/auth/SignupForm.tsx b/frontend/src/components/auth/SignupForm.tsx index 9d20e115..f0654457 100644 --- a/frontend/src/components/auth/SignupForm.tsx +++ b/frontend/src/components/auth/SignupForm.tsx @@ -44,7 +44,7 @@ const SignupForm: React.FC = ({ signupTokenId }) => { } try { - const { error } = await auth.client.POST("/auth/signup", { + const { error } = await auth.client.POST("/auth/email/signup", { body: { signup_token_id: signupTokenId, email: data.email, diff --git a/frontend/src/components/auth/SignupWithEmail.tsx b/frontend/src/components/auth/SignupWithEmail.tsx index 6b9e4d28..d1c594cc 100644 --- a/frontend/src/components/auth/SignupWithEmail.tsx +++ b/frontend/src/components/auth/SignupWithEmail.tsx @@ -25,11 +25,14 @@ const SignupWithEmail = () => { }); const onSubmit = async ({ email }: EmailSignupType) => { - const { data, error } = await auth.client.POST("/email/signup/create", { - body: { - email, + const { data, error } = await auth.client.POST( + "/auth/email/signup/create", + { + body: { + email, + }, }, - }); + ); if (error) { addErrorAlert(error); diff --git a/frontend/src/components/files/URDFRenderer.tsx b/frontend/src/components/files/URDFRenderer.tsx index 58bbe323..f2d2bf0f 100644 --- a/frontend/src/components/files/URDFRenderer.tsx +++ b/frontend/src/components/files/URDFRenderer.tsx @@ -6,6 +6,7 @@ import { FaCompress, FaExpand, FaPlay, + FaSync, FaUndo, } from "react-icons/fa"; @@ -29,14 +30,6 @@ interface URDFInfo { type Theme = "light" | "dark"; -interface Props { - urdfContent: string; - files: UntarredFile[]; - useControls?: boolean; - showWireframe?: boolean; - supportedThemes?: Theme[]; -} - interface ThemeColors { background: string; text: string; @@ -60,12 +53,22 @@ const getThemeColors = (theme: Theme): ThemeColors => { } }; +interface Props { + urdfContent: string; + files: UntarredFile[]; + useControls?: boolean; + showWireframe?: boolean; + supportedThemes?: Theme[]; + overrideColor?: string | null; +} + const URDFRenderer = ({ urdfContent, files, useControls = true, showWireframe = false, supportedThemes = ["light", "dark"], + overrideColor = null, }: Props) => { const containerRef = useRef(null); const sceneRef = useRef(null); @@ -91,6 +94,9 @@ const URDFRenderer = ({ const cameraRef = useRef(null); const controlsRef = useRef(null); + // Add new state/refs for auto-rotation + const [isAutoRotating, setIsAutoRotating] = useState(false); + useEffect(() => { const handleFullScreenChange = () => { const isNowFullScreen = !!document.fullscreenElement; @@ -115,7 +121,7 @@ const URDFRenderer = ({ metalness: 0.4, roughness: 0.5, wireframe: isWireframe, - color: originalColor, + color: overrideColor ? new THREE.Color(overrideColor) : originalColor, }); } }); @@ -184,6 +190,7 @@ const URDFRenderer = ({ controlsRef.current = controls; controls.enableDamping = true; controls.dampingFactor = 0.25; + controls.autoRotateSpeed = 1.0; scene.children.forEach((child) => { if (child instanceof THREE.Light) { @@ -287,11 +294,14 @@ const URDFRenderer = ({ // Setup the animation loop. const animate = () => { - requestAnimationFrame(animate); + const animationId = requestAnimationFrame(animate); controls.update(); + renderer.render(scene, camera); + return animationId; }; - animate(); + + const animationId = animate(); // Handle window resizing. const handleResize = () => { @@ -326,11 +336,37 @@ const URDFRenderer = ({ updateMaterials(); return () => { + if (animationId) { + cancelAnimationFrame(animationId); + } + + scene.traverse((object) => { + if (object instanceof THREE.Mesh) { + if (object.geometry) { + object.geometry.dispose(); + } + if (object.material) { + if (Array.isArray(object.material)) { + object.material.forEach((material) => material.dispose()); + } else { + object.material.dispose(); + } + } + } + }); + + if (renderer) { + renderer.dispose(); + } + if (containerRef.current) { containerRef.current.removeChild(renderer.domElement); } + if (controlsRef.current) { + controlsRef.current.autoRotate = false; + controlsRef.current.dispose(); + } window.removeEventListener("resize", handleResize); - rendererRef.current = null; document.removeEventListener("fullscreenchange", handleFullScreenChange); }; }, [urdfContent, files]); @@ -360,7 +396,7 @@ const URDFRenderer = ({ const startPositions = jointControls.map((joint) => joint.value); const startTime = Date.now(); - const duration = 3000; // Changed from 10000 to 3000 (3 seconds) + const duration = 3000; const animate = () => { const elapsedTime = Date.now() - startTime; @@ -378,15 +414,25 @@ const URDFRenderer = ({ if (progress < 1) { animationRef.current = requestAnimationFrame(animate); } else { - // Reset to original positions jointControls.forEach((_joint, index) => { handleJointChange(index, startPositions[index]); }); setIsCycling(false); + if (animationRef.current) { + cancelAnimationFrame(animationRef.current); + animationRef.current = null; + } } }; animationRef.current = requestAnimationFrame(animate); + + return () => { + if (animationRef.current) { + cancelAnimationFrame(animationRef.current); + animationRef.current = null; + } + }; }, [jointControls, handleJointChange]); const resetJoints = useCallback(() => { @@ -408,6 +454,14 @@ const URDFRenderer = ({ } }, []); + const toggleAutoRotate = useCallback(() => { + const newIsAutoRotating = !isAutoRotating; + if (controlsRef.current) { + controlsRef.current.autoRotate = newIsAutoRotating; + } + setIsAutoRotating(newIsAutoRotating); + }, [isAutoRotating]); + return (
+