mirror of
https://github.com/Dvorinka/excalidraw-full.git
synced 2026-06-04 06:12:56 +00:00
Intercept calls to firebase API
Instead of calling any third-party or home, we provide the stub for firebase API calls.
This commit is contained in:
@@ -0,0 +1,131 @@
|
|||||||
|
package firebase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/go-chi/render"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
BatchGetRequest struct {
|
||||||
|
Documents []string `json:"documents"`
|
||||||
|
}
|
||||||
|
BatchGetEmptyResponse struct {
|
||||||
|
Missing string `json:"missing"`
|
||||||
|
ReadTime string `json:"readTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
FoundInfoResponse struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Fields interface{} `json:"fields"`
|
||||||
|
CreateTime string `json:"createTime"`
|
||||||
|
UpdateTime string `json:"updateTime"`
|
||||||
|
}
|
||||||
|
BatchGetExistsResponse struct {
|
||||||
|
Found FoundInfoResponse `json:"found"`
|
||||||
|
ReadTime string `json:"readTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Fields interface{} `json:"fields"`
|
||||||
|
}
|
||||||
|
WriteRequest struct {
|
||||||
|
Update UpdateRequest `json:"update"`
|
||||||
|
}
|
||||||
|
BatchCommitRequest struct {
|
||||||
|
Writes []WriteRequest `json:"writes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteResult struct {
|
||||||
|
UpdateTime string `json:"updateTime"`
|
||||||
|
}
|
||||||
|
BatchCommitResponse struct {
|
||||||
|
WriteResults []WriteResult `json:"writeResults"`
|
||||||
|
CommitTime string `json:"commitTime"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var savedItems = make(map[string]interface{})
|
||||||
|
|
||||||
|
func (body *BatchGetRequest) Bind(r *http.Request) (err error) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (body *BatchCommitRequest) Bind(r *http.Request) (err error) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func HandleBatchCommit() http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
projectId := chi.URLParam(r, "project_id")
|
||||||
|
databaseId := chi.URLParam(r, "database_id")
|
||||||
|
_ = projectId
|
||||||
|
_ = databaseId
|
||||||
|
|
||||||
|
data := &BatchCommitRequest{}
|
||||||
|
// Seems like requests is text/plain but content is json ...
|
||||||
|
if err := render.DecodeJSON(r.Body, data); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
render.Status(r, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
savedItems[data.Writes[0].Update.Name] = data.Writes[0].Update.Fields
|
||||||
|
|
||||||
|
render.JSON(w, r, BatchCommitResponse{
|
||||||
|
CommitTime: time.Now().Format(time.RFC3339),
|
||||||
|
WriteResults: []WriteResult{
|
||||||
|
WriteResult{UpdateTime: time.Now().Format(time.RFC3339)},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
render.Status(r, http.StatusOK)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleBatchGet() http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
projectId := chi.URLParam(r, "project_id")
|
||||||
|
databaseId := chi.URLParam(r, "database_id")
|
||||||
|
fmt.Printf("Got %v and %v\n", projectId, databaseId)
|
||||||
|
data := &BatchGetRequest{}
|
||||||
|
|
||||||
|
// Seems like requests is text/plain but content is json ...
|
||||||
|
if err := render.DecodeJSON(r.Body, data); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
render.Status(r, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
key := data.Documents[0]
|
||||||
|
fmt.Printf("Got key %v \n", key)
|
||||||
|
|
||||||
|
fields, ok := savedItems[key]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
fmt.Println("missing key")
|
||||||
|
render.JSON(w, r, []BatchGetEmptyResponse{BatchGetEmptyResponse{
|
||||||
|
Missing: key,
|
||||||
|
ReadTime: time.Now().Format(time.RFC3339),
|
||||||
|
}})
|
||||||
|
render.Status(r, http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("existing key")
|
||||||
|
render.JSON(w, r, []BatchGetExistsResponse{BatchGetExistsResponse{
|
||||||
|
Found: FoundInfoResponse{
|
||||||
|
Name: key,
|
||||||
|
Fields: fields,
|
||||||
|
CreateTime: time.Now().Format(time.RFC3339),
|
||||||
|
UpdateTime: time.Now().Format(time.RFC3339),
|
||||||
|
},
|
||||||
|
ReadTime: time.Now().Format(time.RFC3339),
|
||||||
|
}})
|
||||||
|
render.Status(r, http.StatusOK)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,19 +4,23 @@ import (
|
|||||||
"embed"
|
"embed"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"excalidraw-complete/core"
|
"excalidraw-complete/core"
|
||||||
documents "excalidraw-complete/handlers/api"
|
"excalidraw-complete/handlers/api/documents"
|
||||||
|
"excalidraw-complete/handlers/api/firebase"
|
||||||
"excalidraw-complete/stores"
|
"excalidraw-complete/stores"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
"github.com/go-chi/cors"
|
"github.com/go-chi/cors"
|
||||||
"github.com/zishang520/engine.io/v2/types"
|
"github.com/zishang520/engine.io/v2/types"
|
||||||
|
"github.com/zishang520/engine.io/v2/utils"
|
||||||
socketio "github.com/zishang520/socket.io/v2/socket"
|
socketio "github.com/zishang520/socket.io/v2/socket"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -40,7 +44,58 @@ func handleUI() http.Handler {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return http.FileServer(http.FS(sub))
|
// Let's hot-patch all calls to firebase DB
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
originalPath := r.URL.Path
|
||||||
|
originalPath = strings.TrimPrefix(originalPath, "/")
|
||||||
|
fmt.Println(originalPath)
|
||||||
|
file, err := sub.Open(originalPath)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "File not found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
fileContent, err := io.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Error reading file", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
modifiedContent := strings.ReplaceAll(string(fileContent), "firestore.googleapis.com", "localhost:3002")
|
||||||
|
modifiedContent = strings.ReplaceAll(modifiedContent, "ssl=!0", "ssl=0")
|
||||||
|
modifiedContent = strings.ReplaceAll(modifiedContent, "ssl:!0", "ssl:0")
|
||||||
|
if modifiedContent != string(fileContent) {
|
||||||
|
fmt.Println("has replace")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the correct Content-Type based on the file extension
|
||||||
|
contentType := http.DetectContentType([]byte(modifiedContent))
|
||||||
|
switch {
|
||||||
|
case strings.HasSuffix(originalPath, ".js"):
|
||||||
|
contentType = "application/javascript"
|
||||||
|
case strings.HasSuffix(originalPath, ".html"):
|
||||||
|
contentType = "text/html"
|
||||||
|
case strings.HasSuffix(originalPath, ".css"):
|
||||||
|
contentType = "text/css"
|
||||||
|
case strings.HasSuffix(originalPath, ".wasm"):
|
||||||
|
contentType = "application/wasm"
|
||||||
|
case strings.HasSuffix(originalPath, ".tsx"):
|
||||||
|
contentType = "text/typescript"
|
||||||
|
case strings.HasSuffix(originalPath, ".png"):
|
||||||
|
contentType = "image/png"
|
||||||
|
case strings.HasSuffix(originalPath, ".woff2"):
|
||||||
|
contentType = "font/woff2"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve the modified content
|
||||||
|
w.Header().Set("Content-Type", contentType)
|
||||||
|
_, err = w.Write([]byte(modifiedContent))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Error serving file", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupRouter(documentStore core.DocumentStore) *chi.Mux {
|
func setupRouter(documentStore core.DocumentStore) *chi.Mux {
|
||||||
@@ -55,6 +110,11 @@ func setupRouter(documentStore core.DocumentStore) *chi.Mux {
|
|||||||
MaxAge: 300, // Maximum value not ignored by any of major browsers
|
MaxAge: 300, // Maximum value not ignored by any of major browsers
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
r.Route("/v1/projects/{project_id}/databases/{database_id}", func(r chi.Router) {
|
||||||
|
r.Post("/documents:commit", firebase.HandleBatchCommit())
|
||||||
|
r.Post("/documents:batchGet", firebase.HandleBatchGet())
|
||||||
|
})
|
||||||
|
|
||||||
r.Route("/api/v2", func(r chi.Router) {
|
r.Route("/api/v2", func(r chi.Router) {
|
||||||
r.Post("/post/", documents.HandleCreate(documentStore))
|
r.Post("/post/", documents.HandleCreate(documentStore))
|
||||||
r.Route("/{id}", func(r chi.Router) {
|
r.Route("/{id}", func(r chi.Router) {
|
||||||
@@ -72,21 +132,24 @@ func setupSocketIO() *socketio.Server {
|
|||||||
Origin: "*",
|
Origin: "*",
|
||||||
Credentials: true,
|
Credentials: true,
|
||||||
})
|
})
|
||||||
|
opts.SetTransports(types.NewSet("polling", "webtransport"))
|
||||||
ioo := socketio.NewServer(nil, opts)
|
ioo := socketio.NewServer(nil, opts)
|
||||||
|
|
||||||
ioo.On("connection", func(clients ...any) {
|
ioo.On("connection", func(clients ...any) {
|
||||||
socket := clients[0].(*socketio.Socket)
|
socket := clients[0].(*socketio.Socket)
|
||||||
ioo.To(socketio.Room(socket.Id())).Emit("init-room")
|
|
||||||
me := socket.Id()
|
me := socket.Id()
|
||||||
|
myRoom := socketio.Room(me)
|
||||||
|
ioo.To(myRoom).Emit("init-room")
|
||||||
|
utils.Log().Println("init room ", myRoom)
|
||||||
socket.On("join-room", func(datas ...any) {
|
socket.On("join-room", func(datas ...any) {
|
||||||
room := socketio.Room(datas[0].(string))
|
room := socketio.Room(datas[0].(string))
|
||||||
fmt.Printf("Socket %v has joined %v\n", me, room)
|
utils.Log().Printf("Socket %v has joined %v\n", me, room)
|
||||||
socket.Join(room)
|
socket.Join(room)
|
||||||
ioo.In(room).FetchSockets()(func(usersInRoom []*socketio.RemoteSocket, _ error) {
|
ioo.In(room).FetchSockets()(func(usersInRoom []*socketio.RemoteSocket, _ error) {
|
||||||
if len(usersInRoom) <= 1 {
|
if len(usersInRoom) <= 1 {
|
||||||
ioo.To(socketio.Room(me)).Emit("first-in-room")
|
ioo.To(myRoom).Emit("first-in-room")
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("emit new user %v in room %v\n", me, room)
|
utils.Log().Printf("emit new user %v in room %v\n", me, room)
|
||||||
socket.Broadcast().To(room).Emit("new-user", me)
|
socket.Broadcast().To(room).Emit("new-user", me)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +158,7 @@ func setupSocketIO() *socketio.Server {
|
|||||||
for _, user := range usersInRoom {
|
for _, user := range usersInRoom {
|
||||||
newRoomUsers = append(newRoomUsers, user.Id())
|
newRoomUsers = append(newRoomUsers, user.Id())
|
||||||
}
|
}
|
||||||
fmt.Printf(" room %v has users %v\n", room, newRoomUsers)
|
utils.Log().Println(" room ", room, " has users ", newRoomUsers)
|
||||||
ioo.In(room).Emit(
|
ioo.In(room).Emit(
|
||||||
"room-user-change",
|
"room-user-change",
|
||||||
newRoomUsers,
|
newRoomUsers,
|
||||||
@@ -105,12 +168,12 @@ func setupSocketIO() *socketio.Server {
|
|||||||
})
|
})
|
||||||
socket.On("server-broadcast", func(datas ...any) {
|
socket.On("server-broadcast", func(datas ...any) {
|
||||||
roomID := datas[0].(string)
|
roomID := datas[0].(string)
|
||||||
fmt.Printf(" user %v sends update to room %v\n", me, roomID)
|
utils.Log().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.Broadcast().To(socketio.Room(roomID)).Emit("client-broadcast", datas[1], datas[2])
|
||||||
})
|
})
|
||||||
socket.On("server-volatile-broadcast", func(datas ...any) {
|
socket.On("server-volatile-broadcast", func(datas ...any) {
|
||||||
roomID := datas[0].(string)
|
roomID := datas[0].(string)
|
||||||
fmt.Printf(" user %v sends volatile update to room %v\n", me, roomID)
|
utils.Log().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.Volatile().Broadcast().To(socketio.Room(roomID)).Emit("client-broadcast", datas[1], datas[2])
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -121,20 +184,18 @@ func setupSocketIO() *socketio.Server {
|
|||||||
socket.On("disconnecting", func(datas ...any) {
|
socket.On("disconnecting", func(datas ...any) {
|
||||||
for _, currentRoom := range socket.Rooms().Keys() {
|
for _, currentRoom := range socket.Rooms().Keys() {
|
||||||
ioo.In(currentRoom).FetchSockets()(func(usersInRoom []*socketio.RemoteSocket, _ error) {
|
ioo.In(currentRoom).FetchSockets()(func(usersInRoom []*socketio.RemoteSocket, _ error) {
|
||||||
allUsers := []socketio.SocketId{}
|
otherClients := []socketio.SocketId{}
|
||||||
remainingUsers := []socketio.SocketId{}
|
utils.Log().Printf("disconnecting %v from room %v\n", me, currentRoom)
|
||||||
fmt.Printf("disconnecting %v from room %v\n", me, currentRoom)
|
|
||||||
for _, userInRoom := range usersInRoom {
|
for _, userInRoom := range usersInRoom {
|
||||||
allUsers = append(allUsers, userInRoom.Id())
|
|
||||||
if userInRoom.Id() != me {
|
if userInRoom.Id() != me {
|
||||||
remainingUsers = append(remainingUsers, userInRoom.Id())
|
otherClients = append(otherClients, userInRoom.Id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(remainingUsers) > 0 {
|
if len(otherClients) > 0 {
|
||||||
fmt.Printf("leaving user, room %v has users %v -> %v\n", currentRoom, allUsers, remainingUsers)
|
utils.Log().Printf("leaving user, room %v has users %v\n", currentRoom, otherClients)
|
||||||
ioo.In(currentRoom).Emit(
|
ioo.In(currentRoom).Emit(
|
||||||
"room-user-change",
|
"room-user-change",
|
||||||
remainingUsers,
|
otherClients,
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -149,6 +210,7 @@ func setupSocketIO() *socketio.Server {
|
|||||||
socket.Disconnect(true)
|
socket.Disconnect(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
utils.Log().Println("%v", ioo)
|
||||||
return ioo
|
return ioo
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user