this repo has no description
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: broadcast changes

authored by

Anish Lakhwara and committed by
sōm
2da88321 d785dde3

+208 -9
+9 -7
mast-react-vite/src/App.tsx
··· 306 306 setNewText(""); 307 307 308 308 // Explicitly tell the worker to sync changes after modifying the database 309 - console.log("Database changed - triggering sync"); 310 - setTimeout(() => { 311 - syncWorker.postMessage({ 312 - type: 'SYNC_CHANGES', 313 - dbname 314 - }); 315 - }, 100); // Small delay to ensure changes are committed 309 + if (parsed.action !== "filter") { // Only sync for data-changing operations 310 + console.log("Database changed - triggering sync"); 311 + setTimeout(() => { 312 + syncWorker.postMessage({ 313 + type: 'SYNC_CHANGES', 314 + dbname 315 + }); 316 + }, 100); // Small delay to ensure changes are committed 317 + } 316 318 } catch (error) { 317 319 // TODO: 318 320 // This is actually bad
+59
mast-react-vite/src/components/ui/alert.tsx
··· 1 + import * as React from "react" 2 + import { cva, type VariantProps } from "class-variance-authority" 3 + 4 + import { cn } from "@/lib/utils" 5 + 6 + const alertVariants = cva( 7 + "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7", 8 + { 9 + variants: { 10 + variant: { 11 + default: "bg-background text-foreground", 12 + destructive: 13 + "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", 14 + }, 15 + }, 16 + defaultVariants: { 17 + variant: "default", 18 + }, 19 + } 20 + ) 21 + 22 + const Alert = React.forwardRef< 23 + HTMLDivElement, 24 + React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants> 25 + >(({ className, variant, ...props }, ref) => ( 26 + <div 27 + ref={ref} 28 + role="alert" 29 + className={cn(alertVariants({ variant }), className)} 30 + {...props} 31 + /> 32 + )) 33 + Alert.displayName = "Alert" 34 + 35 + const AlertTitle = React.forwardRef< 36 + HTMLParagraphElement, 37 + React.HTMLAttributes<HTMLHeadingElement> 38 + >(({ className, ...props }, ref) => ( 39 + <h5 40 + ref={ref} 41 + className={cn("mb-1 font-medium leading-none tracking-tight", className)} 42 + {...props} 43 + /> 44 + )) 45 + AlertTitle.displayName = "AlertTitle" 46 + 47 + const AlertDescription = React.forwardRef< 48 + HTMLParagraphElement, 49 + React.HTMLAttributes<HTMLParagraphElement> 50 + >(({ className, ...props }, ref) => ( 51 + <div 52 + ref={ref} 53 + className={cn("text-sm [&_p]:leading-relaxed", className)} 54 + {...props} 55 + /> 56 + )) 57 + AlertDescription.displayName = "AlertDescription" 58 + 59 + export { Alert, AlertTitle, AlertDescription }
+1 -1
mast-react-vite/src/components/ui/app-sidebar.tsx
··· 104 104 <SidebarFooter /> 105 105 </Sidebar> 106 106 ); 107 - } 107 + }
+119
mast-react-vite/src/components/ui/dialog.tsx
··· 1 + import * as React from "react" 2 + import * as DialogPrimitive from "@radix-ui/react-dialog" 3 + import { cn } from "@/lib/utils" 4 + import { Cross2Icon } from "@radix-ui/react-icons" 5 + 6 + const Dialog = DialogPrimitive.Root 7 + 8 + const DialogTrigger = DialogPrimitive.Trigger 9 + 10 + const DialogPortal = DialogPrimitive.Portal 11 + 12 + const DialogClose = DialogPrimitive.Close 13 + 14 + const DialogOverlay = React.forwardRef< 15 + React.ElementRef<typeof DialogPrimitive.Overlay>, 16 + React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> 17 + >(({ className, ...props }, ref) => ( 18 + <DialogPrimitive.Overlay 19 + ref={ref} 20 + className={cn( 21 + "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", 22 + className 23 + )} 24 + {...props} 25 + /> 26 + )) 27 + DialogOverlay.displayName = DialogPrimitive.Overlay.displayName 28 + 29 + const DialogContent = React.forwardRef< 30 + React.ElementRef<typeof DialogPrimitive.Content>, 31 + React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> 32 + >(({ className, children, ...props }, ref) => ( 33 + <DialogPortal> 34 + <DialogOverlay /> 35 + <DialogPrimitive.Content 36 + ref={ref} 37 + className={cn( 38 + "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", 39 + className 40 + )} 41 + {...props} 42 + > 43 + {children} 44 + <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"> 45 + <Cross2Icon className="h-4 w-4" /> 46 + <span className="sr-only">Close</span> 47 + </DialogPrimitive.Close> 48 + </DialogPrimitive.Content> 49 + </DialogPortal> 50 + )) 51 + DialogContent.displayName = DialogPrimitive.Content.displayName 52 + 53 + const DialogHeader = ({ 54 + className, 55 + ...props 56 + }: React.HTMLAttributes<HTMLDivElement>) => ( 57 + <div 58 + className={cn( 59 + "flex flex-col space-y-1.5 text-center sm:text-left", 60 + className 61 + )} 62 + {...props} 63 + /> 64 + ) 65 + DialogHeader.displayName = "DialogHeader" 66 + 67 + const DialogFooter = ({ 68 + className, 69 + ...props 70 + }: React.HTMLAttributes<HTMLDivElement>) => ( 71 + <div 72 + className={cn( 73 + "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", 74 + className 75 + )} 76 + {...props} 77 + /> 78 + ) 79 + DialogFooter.displayName = "DialogFooter" 80 + 81 + const DialogTitle = React.forwardRef< 82 + React.ElementRef<typeof DialogPrimitive.Title>, 83 + React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> 84 + >(({ className, ...props }, ref) => ( 85 + <DialogPrimitive.Title 86 + ref={ref} 87 + className={cn( 88 + "text-lg font-semibold leading-none tracking-tight", 89 + className 90 + )} 91 + {...props} 92 + /> 93 + )) 94 + DialogTitle.displayName = DialogPrimitive.Title.displayName 95 + 96 + const DialogDescription = React.forwardRef< 97 + React.ElementRef<typeof DialogPrimitive.Description>, 98 + React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> 99 + >(({ className, ...props }, ref) => ( 100 + <DialogPrimitive.Description 101 + ref={ref} 102 + className={cn("text-sm text-muted-foreground", className)} 103 + {...props} 104 + /> 105 + )) 106 + DialogDescription.displayName = DialogPrimitive.Description.displayName 107 + 108 + export { 109 + Dialog, 110 + DialogPortal, 111 + DialogOverlay, 112 + DialogTrigger, 113 + DialogClose, 114 + DialogContent, 115 + DialogHeader, 116 + DialogFooter, 117 + DialogTitle, 118 + DialogDescription, 119 + }
+10
mast-react-vite/src/worker/sync-worker.ts
··· 447 447 logDebug(`Updated lastSyncVersion to ${maxVersion}`); 448 448 } 449 449 450 + // Notify main thread that changes were applied and force a query refresh 451 + try { 452 + // This will trigger a database update event that @vlcn.io/rx-tbl will detect 453 + // Force a dummy statement that touches the database to trigger update subscriptions 454 + // Creating a temporary table will cause SQLite to touch the database file 455 + await connection.db.exec('SELECT 1;'); 456 + } catch (error) { 457 + logError('Error triggering database refresh:', error); 458 + } 459 + 450 460 // Notify main thread that changes were applied 451 461 self.postMessage({ type: 'CHANGES_APPLIED', dbname, count: changes.length }); 452 462
+10 -1
server/main.go
··· 89 89 roomsMu.Unlock() 90 90 91 91 if !exists { 92 + log.Printf("Room %s not found for broadcasting", roomID) 92 93 return 93 94 } 94 95 95 96 room.mu.Lock() 96 97 defer room.mu.Unlock() 97 98 99 + clientCount := 0 98 100 for client := range room.clients { 99 101 if client != sender { 100 - client.WriteMessage(websocket.TextMessage, message) 102 + clientCount++ 103 + err := client.WriteMessage(websocket.TextMessage, message) 104 + if err != nil { 105 + log.Printf("Error broadcasting to client: %v", err) 106 + } 101 107 } 102 108 } 109 + log.Printf("Broadcasted changes to %d clients in room %s", clientCount, roomID) 103 110 } 104 111 105 112 func handleWebSocket(w http.ResponseWriter, r *http.Request) { ··· 202 209 applyChangesToDB(db, data) 203 210 204 211 // Broadcast changes to other clients in the same room 212 + log.Printf("Broadcasting changes to other clients in room %s", roomID) 205 213 broadcastToRoom(roomID, conn, message) 214 + log.Printf("Broadcast completed for room %s", roomID) 206 215 } 207 216 } 208 217 }