websocket-based lrcproto server

add batchedits

+48 -3
+1 -1
go.mod
··· 4 4 5 5 require ( 6 6 github.com/gorilla/websocket v1.5.3 7 - github.com/rachel-mp4/lrcproto v0.0.0-20250720164211-c6162669b709 7 + github.com/rachel-mp4/lrcproto v0.0.0-20250905151943-8e3a1989ea5a 8 8 google.golang.org/protobuf v1.36.6 9 9 )
+4
go.sum
··· 4 4 github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 5 5 github.com/rachel-mp4/lrcproto v0.0.0-20250720164211-c6162669b709 h1:P//gJE0zFv9Qvfn8dvp9ZrnG0FZh2MVcAX+uOP2flRw= 6 6 github.com/rachel-mp4/lrcproto v0.0.0-20250720164211-c6162669b709/go.mod h1:hQzO36tQELGbkmRnUtKeM6NMU34t79ZcTlhM+MO7pHw= 7 + github.com/rachel-mp4/lrcproto v0.0.0-20250905145450-74a49183ee1f h1:CZVsuwuS/5fDwB4X9AgobE1bjnhVFaIuedgZOuVtqeA= 8 + github.com/rachel-mp4/lrcproto v0.0.0-20250905145450-74a49183ee1f/go.mod h1:hQzO36tQELGbkmRnUtKeM6NMU34t79ZcTlhM+MO7pHw= 9 + github.com/rachel-mp4/lrcproto v0.0.0-20250905151943-8e3a1989ea5a h1:W3zPeGz/jHYyWj8ZfsuA9yigPMNlA/h7Fu+SQKgiBmQ= 10 + github.com/rachel-mp4/lrcproto v0.0.0-20250905151943-8e3a1989ea5a/go.mod h1:hQzO36tQELGbkmRnUtKeM6NMU34t79ZcTlhM+MO7pHw= 7 11 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 8 12 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 9 13 google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
+43 -2
server.go
··· 252 252 client.cancel() 253 253 return 254 254 } 255 - s.eventBus <- clientEvent{client, &event} 255 + s.eventBus <- clientEvent{client: client, event: &event} 256 256 } 257 257 } 258 258 } ··· 319 319 s.handleSet(msg, client) 320 320 case *lrcpb.Event_Get: 321 321 s.handleGet(msg, client) 322 + case *lrcpb.Event_Editbatch: 323 + s.handleEditBatch(msg, client) 322 324 } 325 + 323 326 } 324 327 } 325 328 } ··· 473 476 resultRunes := utf16.Decode(result) 474 477 return string(resultRunes), nil 475 478 } 476 - 477 479 func (s *Server) broadcast(event *lrcpb.Event, client *client) { 480 + data, _ := proto.Marshal(event) 481 + s.clientsMu.Lock() 482 + defer s.clientsMu.Unlock() 483 + for c := range s.clients { 484 + if client.mutedBy[c] { 485 + continue 486 + } 487 + select { 488 + case c.dataChan <- data: 489 + s.logDebug("b") 490 + default: 491 + s.log("kicked client") 492 + client.cancel() 493 + } 494 + } 495 + } 496 + 497 + func (s *Server) handleEditBatch(msg *lrcpb.Event_Editbatch, client *client) { 498 + curID := s.clientToID[client] 499 + if curID == nil { 500 + return 501 + } 502 + for _, edit := range msg.Editbatch.Edits { 503 + switch edit := edit.Edit.(type) { 504 + case *lrcpb.Edit_Insert: 505 + inserted, err := insertAtUTF16Index(*client.post, edit.Insert.GetUtf16Index(), edit.Insert.GetBody()) 506 + if err != nil { 507 + return 508 + } 509 + client.post = &inserted 510 + case *lrcpb.Edit_Delete: 511 + deleted, err := deleteBtwnUTF16Indices(*client.post, edit.Delete.GetUtf16Start(), edit.Delete.GetUtf16End()) 512 + if err != nil { 513 + return 514 + } 515 + client.post = &deleted 516 + } 517 + } 518 + event := &lrcpb.Event{Msg: msg, Id: curID} 478 519 data, _ := proto.Marshal(event) 479 520 s.clientsMu.Lock() 480 521 defer s.clientsMu.Unlock()