main.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. package main
  2. import (
  3. "bytes"
  4. "excalidraw-backend/core"
  5. "excalidraw-backend/documents/memory"
  6. "fmt"
  7. "io"
  8. "net/http"
  9. "os"
  10. "os/signal"
  11. "syscall"
  12. "github.com/go-chi/chi/v5"
  13. "github.com/go-chi/chi/v5/middleware"
  14. "github.com/go-chi/cors"
  15. "github.com/go-chi/render"
  16. "github.com/oklog/ulid/v2"
  17. "github.com/zishang520/engine.io/v2/types"
  18. socketio "github.com/zishang520/socket.io/v2/socket"
  19. )
  20. type (
  21. DocumentCreateResponse struct {
  22. ID string `json:"id"`
  23. }
  24. UserToFollow struct {
  25. SocketId string
  26. Username string
  27. }
  28. OnUserFollowedPayload struct {
  29. UserToFollow UserToFollow
  30. action string
  31. }
  32. )
  33. func main() {
  34. opts := socketio.DefaultServerOptions()
  35. opts.SetMaxHttpBufferSize(5000000)
  36. opts.SetPath("/socket.io")
  37. opts.SetAllowEIO3(true)
  38. opts.SetCors(&types.Cors{
  39. Origin: "*",
  40. Credentials: true,
  41. })
  42. ioo := socketio.NewServer(nil, opts)
  43. ioo.On("connection", func(clients ...any) {
  44. socket := clients[0].(*socketio.Socket)
  45. ioo.To(socketio.Room(socket.Id())).Emit("init-room")
  46. me := socket.Id()
  47. socket.On("join-room", func(datas ...any) {
  48. room := socketio.Room(datas[0].(string))
  49. fmt.Printf("Socket %v has joined %v\n", me, room)
  50. socket.Join(room)
  51. ioo.In(room).FetchSockets()(func(sockets []*socketio.RemoteSocket, _ error) {
  52. if len(sockets) <= 1 {
  53. ioo.To(socketio.Room(socket.Id())).Emit("first-in-room")
  54. } else {
  55. fmt.Printf("emit new user %v in room %v\n", me, room)
  56. socket.Broadcast().To(room).Emit("new-user", me)
  57. }
  58. data := []socketio.SocketId{}
  59. for _, osocket := range sockets {
  60. data = append(data, osocket.Id())
  61. }
  62. fmt.Printf(" room %v has users %v\n", room, data)
  63. ioo.In(room).Emit(
  64. "room-user-change",
  65. data,
  66. )
  67. })
  68. })
  69. socket.On("server-broadcast", func(datas ...any) {
  70. roomID := datas[0].(string)
  71. fmt.Printf(" user %v sends update to room %v\n", me, roomID)
  72. socket.Broadcast().To(socketio.Room(roomID)).Emit("client-broadcast", datas[1], datas[2])
  73. })
  74. socket.On("server-volatile-broadcast", func(datas ...any) {
  75. roomID := datas[0].(string)
  76. fmt.Printf(" user %v sends volatile update to room %v\n", me, roomID)
  77. socket.Volatile().Broadcast().To(socketio.Room(roomID)).Emit("client-broadcast", datas[1], datas[2])
  78. })
  79. socket.On("user-follow", func(datas ...any) {
  80. // TODO()
  81. })
  82. socket.On("disconnecting", func(datas ...any) {
  83. for _, oroom := range socket.Rooms().Keys() {
  84. ioo.In(oroom).FetchSockets()(func(sockets []*socketio.RemoteSocket, _ error) {
  85. otherClients := []socketio.SocketId{}
  86. fmt.Printf("disconnecting %v from room %v", me, oroom)
  87. for _, osocket := range sockets {
  88. if osocket.Id() != me {
  89. otherClients = append(otherClients, osocket.Id())
  90. fmt.Println("other", osocket.Id())
  91. }
  92. }
  93. if len(otherClients) > 0 {
  94. ioo.In(oroom).Emit(
  95. "room-user-change",
  96. otherClients,
  97. )
  98. }
  99. })
  100. }
  101. })
  102. socket.On("disconnect", func(datas ...any) {
  103. socket.RemoveAllListeners("")
  104. socket.Disconnect(true)
  105. })
  106. })
  107. r := chi.NewRouter()
  108. r.Use(middleware.Logger)
  109. r.Use(cors.Handler(cors.Options{
  110. AllowedOrigins: []string{"https://*", "http://*"},
  111. AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
  112. AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "Content-Length", "X-CSRF-Token", "Token", "session", "Origin", "Host", "Connection", "Accept-Encoding", "Accept-Language", "X-Requested-With"},
  113. AllowCredentials: true,
  114. MaxAge: 300, // Maximum value not ignored by any of major browsers
  115. }))
  116. documentStore := memory.NewDocumentStore()
  117. r.Get("/", func(w http.ResponseWriter, r *http.Request) {
  118. w.Write([]byte("you are all set"))
  119. fmt.Println(ulid.Make())
  120. render.Status(r, http.StatusOK)
  121. })
  122. r.Route("/api/v2", func(r chi.Router) {
  123. r.Post("/post/", func(w http.ResponseWriter, r *http.Request) {
  124. data := new(bytes.Buffer)
  125. _, err := io.Copy(data, r.Body)
  126. if err != nil {
  127. http.Error(w, "Failed to copy", http.StatusInternalServerError)
  128. return
  129. }
  130. id, err := documentStore.Create(r.Context(), &core.Document{Data: *data})
  131. if err != nil {
  132. http.Error(w, "Failed to save", http.StatusInternalServerError)
  133. return
  134. }
  135. render.JSON(w, r, DocumentCreateResponse{ID: id})
  136. render.Status(r, http.StatusOK)
  137. })
  138. r.Route("/{id}", func(r chi.Router) {
  139. r.Get("/", func(w http.ResponseWriter, r *http.Request) {
  140. id := chi.URLParam(r, "id")
  141. document, err := documentStore.FindID(r.Context(), id)
  142. if err != nil {
  143. http.Error(w, "not found", http.StatusNotFound)
  144. return
  145. }
  146. w.Write(document.Data.Bytes())
  147. })
  148. })
  149. })
  150. r.Handle("/socket.io/", ioo.ServeHandler(nil))
  151. go http.ListenAndServe(":3002", r)
  152. exit := make(chan struct{})
  153. SignalC := make(chan os.Signal)
  154. signal.Notify(SignalC, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
  155. go func() {
  156. for s := range SignalC {
  157. switch s {
  158. case os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
  159. close(exit)
  160. return
  161. }
  162. }
  163. }()
  164. <-exit
  165. ioo.Close(nil)
  166. os.Exit(0)
  167. }