Initial prototype

This commit is contained in:
patwie
2024-03-28 23:55:02 +00:00
commit 36e3ecb5c7
9 changed files with 475 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
dist/
excalidraw-backend
+51
View File
@@ -0,0 +1,51 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
# The lines below are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/need to use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
version: 1
# before:
# hooks:
# # You may remove this if you don't use go modules.
# - go mod tidy
# # you may remove this if you don't need go generate
# - go generate ./...
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
archives:
- format: tar.gz
files: []
# this name template makes the OS and Arch compatible with the results of `uname`.
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
# use zip for windows archives
format_overrides:
- goos: windows
format: zip
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
release:
disable: true
skip_upload: true
+12
View File
@@ -0,0 +1,12 @@
# Exalidraw Backend
Frustrated on how difficult it is to setup excalidraw self-hosted but with data
storage and collaboration function this represents and attempt to run the
necessary function with a single binary implemented in go.
Apply the patch to the frontend and build excalidraw. Run Excalidraw frontend and
on the same host run
```bash
go run main.go
```
+17
View File
@@ -0,0 +1,17 @@
package core
import (
"bytes"
"context"
)
type (
Document struct {
Data bytes.Buffer
}
DocumentStore interface {
FindID(ctx context.Context, id string) (*Document, error)
Create(ctx context.Context, document *Document) (string, error)
}
)
+31
View File
@@ -0,0 +1,31 @@
package memory
import (
"context"
"excalidraw-backend/core"
"fmt"
"github.com/oklog/ulid/v2"
)
var savedDocuments = make(map[string]core.Document)
type documentStore struct {
}
func NewDocumentStore() core.DocumentStore {
return &documentStore{}
}
func (s *documentStore) FindID(ctx context.Context, id string) (*core.Document, error) {
if val, ok := savedDocuments[id]; ok {
return &val, nil
}
return nil, fmt.Errorf("document with id %s not found", id)
}
func (s *documentStore) Create(ctx context.Context, document *core.Document) (string, error) {
id := ulid.Make().String()
savedDocuments[id] = *document
return id, nil
}
+40
View File
@@ -0,0 +1,40 @@
diff --git a/.env.production b/.env.production
index 0c715854..422add5c 100644
--- a/.env.production
+++ b/.env.production
@@ -1,17 +1,25 @@
-VITE_APP_BACKEND_V2_GET_URL=https://json.excalidraw.com/api/v2/
-VITE_APP_BACKEND_V2_POST_URL=https://json.excalidraw.com/api/v2/post/
+# VITE_APP_BACKEND_V2_GET_URL=https://json.excalidraw.com/api/v2/
+# VITE_APP_BACKEND_V2_POST_URL=https://json.excalidraw.com/api/v2/post/
+VITE_APP_BACKEND_V2_GET_URL=http://localhost:3002/api/v2/
+VITE_APP_BACKEND_V2_POST_URL=http://localhost:3002/api/v2/post/
VITE_APP_LIBRARY_URL=https://libraries.excalidraw.com
-VITE_APP_LIBRARY_BACKEND=https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries
+# VITE_APP_LIBRARY_BACKEND=https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries
+VITE_APP_LIBRARY_BACKEND=http://localhost:3002/libraries
+# VITE_APP_PLUS_LP=https://plus.excalidraw.com
+VITE_APP_PLUS_LP=http://localhost:3002/plus/
+# VITE_APP_PLUS_APP=https://app.excalidraw.com
+VITE_APP_PLUS_APP=http://localhost:3002/app/
-VITE_APP_PLUS_LP=https://plus.excalidraw.com
-VITE_APP_PLUS_APP=https://app.excalidraw.com
-
-VITE_APP_AI_BACKEND=https://oss-ai.excalidraw.com
+# VITE_APP_AI_BACKEND=https://oss-ai.excalidraw.com
+VITE_APP_AI_BACKEND=http://localhost:3002/ai/
# socket server URL used for collaboration
-VITE_APP_WS_SERVER_URL=https://oss-collab.excalidraw.com
+VITE_APP_WS_SERVER_URL=http://localhost:3002
+# VITE_APP_WS_SERVER_URL=https://oss-collab.excalidraw.com
-VITE_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyAd15pYlMci_xIp9ko6wkEsDzAAA0Dn0RU","authDomain":"excalidraw-room-persistence.firebaseapp.com","databaseURL":"https://excalidraw-room-persistence.firebaseio.com","projectId":"excalidraw-room-persistence","storageBucket":"excalidraw-room-persistence.appspot.com","messagingSenderId":"654800341332","appId":"1:654800341332:web:4a692de832b55bd57ce0c1"}'
+# VITE_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyAd15pYlMci_xIp9ko6wkEsDzAAA0Dn0RU","authDomain":"excalidraw-room-persistence.firebaseapp.com","databaseURL":"https://excalidraw-room-persistence.firebaseio.com","projectId":"excalidraw-room-persistence","storageBucket":"excalidraw-room-persistence.appspot.com","messagingSenderId":"654800341332","appId":"1:654800341332:web:4a692de832b55bd57ce0c1"}'
+VITE_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyAd15pYlMci_xIp9ko6wkEsDzAAA0Dn0RU","authDomain":"","databaseURL":"","projectId":"excalidraw-room-persistence","storageBucket":"","messagingSenderId":"654800341332","appId":"1:654800341332:web:4a692de832b55bd57ce0c1"}'
-VITE_APP_DISABLE_TRACKING=
+# VITE_APP_DISABLE_TRACKING=
+VITE_APP_DISABLE_TRACKING=yes
+42
View File
@@ -0,0 +1,42 @@
module excalidraw-backend
go 1.21
toolchain go1.22.1
require (
github.com/go-chi/chi/v5 v5.0.12
github.com/go-chi/cors v1.2.1
github.com/go-chi/render v1.0.3
github.com/oklog/ulid/v2 v2.1.0
github.com/zishang520/engine.io/v2 v2.0.6
github.com/zishang520/socket.io/v2 v2.0.5
)
require (
github.com/ajg/form v1.5.1 // indirect
github.com/andybalholm/brotli v1.0.6 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/onsi/ginkgo/v2 v2.12.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
github.com/quic-go/quic-go v0.40.1 // indirect
github.com/quic-go/webtransport-go v0.6.0 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
github.com/zishang520/engine.io-go-parser v1.2.3 // indirect
github.com/zishang520/socket.io-go-parser/v2 v2.0.4 // indirect
go.uber.org/mock v0.3.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect
)
+88
View File
@@ -0,0 +1,88 @@
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f h1:pDhu5sgp8yJlEF/g6osliIIpF9K4F5jvkULXa4daRDQ=
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/onsi/ginkgo/v2 v2.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI=
github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q=
github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY=
github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
github.com/zishang520/engine.io-go-parser v1.2.3 h1:y++zdMKIFgyVvH60TEEHw8gdJkS/qy22wesdALoh+HA=
github.com/zishang520/engine.io-go-parser v1.2.3/go.mod h1:UrXBVZWQgyHDITYmhnxi2d+NpEWBN8dACboD4dXcx38=
github.com/zishang520/engine.io/v2 v2.0.6 h1:hXZRwSoZql7xgxbW4xupRjDDLUXcwo/pYSlWc6dNCAk=
github.com/zishang520/engine.io/v2 v2.0.6/go.mod h1:M908EfW1x3hf+GIONy5x9ZOeeYsPOwUImxyuTabtsYA=
github.com/zishang520/socket.io-go-parser/v2 v2.0.4 h1:PxzWPrTxueiKXFZJQduJ9sIIzsBbHMi9XO5nTLbIjS4=
github.com/zishang520/socket.io-go-parser/v2 v2.0.4/go.mod h1:fei4NeEGrSJK+uQPnuI4WVm8h+WLF/kVpDHVjeI+0bA=
github.com/zishang520/socket.io/v2 v2.0.5 h1:CImu9z6YKFif2mMX2b3y2OUhxxH8nz01PqP6+W6dXy4=
github.com/zishang520/socket.io/v2 v2.0.5/go.mod h1:r+spG2g+Q0lxhgTHevGl7/h4DzkKrO00i8AEF9vj2PQ=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+192
View File
@@ -0,0 +1,192 @@
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)
}