| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- package main
- import (
- "bytes"
- "excalidraw-backend/core"
- "excalidraw-backend/documents/memory"
- "fmt"
- "io"
- "net/http"
- "os"
- "os/signal"
- "syscall"
- "github.com/go-chi/chi/v5"
- "github.com/go-chi/chi/v5/middleware"
- "github.com/go-chi/cors"
- "github.com/go-chi/render"
- "github.com/oklog/ulid/v2"
- "github.com/zishang520/engine.io/v2/types"
- socketio "github.com/zishang520/socket.io/v2/socket"
- )
- type (
- DocumentCreateResponse struct {
- ID string `json:"id"`
- }
- UserToFollow struct {
- SocketId string
- Username string
- }
- OnUserFollowedPayload struct {
- UserToFollow UserToFollow
- action string
- }
- )
- func main() {
- opts := socketio.DefaultServerOptions()
- opts.SetMaxHttpBufferSize(5000000)
- opts.SetPath("/socket.io")
- opts.SetAllowEIO3(true)
- opts.SetCors(&types.Cors{
- Origin: "*",
- Credentials: true,
- })
- ioo := socketio.NewServer(nil, opts)
- ioo.On("connection", func(clients ...any) {
- socket := clients[0].(*socketio.Socket)
- ioo.To(socketio.Room(socket.Id())).Emit("init-room")
- me := socket.Id()
- socket.On("join-room", func(datas ...any) {
- room := socketio.Room(datas[0].(string))
- fmt.Printf("Socket %v has joined %v\n", me, room)
- socket.Join(room)
- ioo.In(room).FetchSockets()(func(sockets []*socketio.RemoteSocket, _ error) {
- if len(sockets) <= 1 {
- ioo.To(socketio.Room(socket.Id())).Emit("first-in-room")
- } else {
- fmt.Printf("emit new user %v in room %v\n", me, room)
- socket.Broadcast().To(room).Emit("new-user", me)
- }
- data := []socketio.SocketId{}
- for _, osocket := range sockets {
- data = append(data, osocket.Id())
- }
- fmt.Printf(" room %v has users %v\n", room, data)
- ioo.In(room).Emit(
- "room-user-change",
- data,
- )
- })
- })
- socket.On("server-broadcast", func(datas ...any) {
- roomID := datas[0].(string)
- fmt.Printf(" user %v sends update to room %v\n", me, roomID)
- socket.Broadcast().To(socketio.Room(roomID)).Emit("client-broadcast", datas[1], datas[2])
- })
- socket.On("server-volatile-broadcast", func(datas ...any) {
- roomID := datas[0].(string)
- fmt.Printf(" user %v sends volatile update to room %v\n", me, roomID)
- socket.Volatile().Broadcast().To(socketio.Room(roomID)).Emit("client-broadcast", datas[1], datas[2])
- })
- socket.On("user-follow", func(datas ...any) {
- // TODO()
- })
- socket.On("disconnecting", func(datas ...any) {
- for _, oroom := range socket.Rooms().Keys() {
- ioo.In(oroom).FetchSockets()(func(sockets []*socketio.RemoteSocket, _ error) {
- otherClients := []socketio.SocketId{}
- fmt.Printf("disconnecting %v from room %v", me, oroom)
- for _, osocket := range sockets {
- if osocket.Id() != me {
- otherClients = append(otherClients, osocket.Id())
- fmt.Println("other", osocket.Id())
- }
- }
- if len(otherClients) > 0 {
- ioo.In(oroom).Emit(
- "room-user-change",
- otherClients,
- )
- }
- })
- }
- })
- socket.On("disconnect", func(datas ...any) {
- socket.RemoveAllListeners("")
- socket.Disconnect(true)
- })
- })
- r := chi.NewRouter()
- r.Use(middleware.Logger)
- r.Use(cors.Handler(cors.Options{
- AllowedOrigins: []string{"https://*", "http://*"},
- AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
- AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "Content-Length", "X-CSRF-Token", "Token", "session", "Origin", "Host", "Connection", "Accept-Encoding", "Accept-Language", "X-Requested-With"},
- AllowCredentials: true,
- MaxAge: 300, // Maximum value not ignored by any of major browsers
- }))
- documentStore := memory.NewDocumentStore()
- r.Get("/", func(w http.ResponseWriter, r *http.Request) {
- w.Write([]byte("you are all set"))
- fmt.Println(ulid.Make())
- render.Status(r, http.StatusOK)
- })
- r.Route("/api/v2", func(r chi.Router) {
- r.Post("/post/", func(w http.ResponseWriter, r *http.Request) {
- data := new(bytes.Buffer)
- _, err := io.Copy(data, r.Body)
- if err != nil {
- http.Error(w, "Failed to copy", http.StatusInternalServerError)
- return
- }
- id, err := documentStore.Create(r.Context(), &core.Document{Data: *data})
- if err != nil {
- http.Error(w, "Failed to save", http.StatusInternalServerError)
- return
- }
- render.JSON(w, r, DocumentCreateResponse{ID: id})
- render.Status(r, http.StatusOK)
- })
- r.Route("/{id}", func(r chi.Router) {
- r.Get("/", func(w http.ResponseWriter, r *http.Request) {
- id := chi.URLParam(r, "id")
- document, err := documentStore.FindID(r.Context(), id)
- if err != nil {
- http.Error(w, "not found", http.StatusNotFound)
- return
- }
- w.Write(document.Data.Bytes())
- })
- })
- })
- r.Handle("/socket.io/", ioo.ServeHandler(nil))
- go http.ListenAndServe(":3002", r)
- exit := make(chan struct{})
- SignalC := make(chan os.Signal)
- signal.Notify(SignalC, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
- go func() {
- for s := range SignalC {
- switch s {
- case os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
- close(exit)
- return
- }
- }
- }()
- <-exit
- ioo.Close(nil)
- os.Exit(0)
- }
|