Skip to content

Commit 2d81575

Browse files
committed
improvements
1 parent 56c354e commit 2d81575

File tree

2 files changed

+98
-45
lines changed

2 files changed

+98
-45
lines changed

internal/backend/automergesyncmanager.go

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package backend
22

33
import (
4+
"encoding/base64"
45
"errors"
56
"fmt"
67
automerge "github.com/automerge/automerge-go"
@@ -11,20 +12,31 @@ import (
1112

1213
type (
1314
SyncRequest struct {
14-
Type string `json:"type" xml:"type" form:"type" query:"type"`
15-
RequestId string `json:"requestId" xml:"requestId" form:"requestId" query:"requestId"`
16-
DocumentId string `json:"documentId" xml:"documentId" form:"documentId" query:"documentId"`
17-
SyncState *automerge.SyncMessage `json:"syncState" xml:"syncState" form:"syncState" query:"syncState"`
15+
Type string `json:"type" xml:"type" form:"type" query:"type"`
16+
RequestId string `json:"requestId" xml:"requestId" form:"requestId" query:"requestId"`
17+
DocumentId string `json:"documentId" xml:"documentId" form:"documentId" query:"documentId"`
18+
// *automerge.Doc as base64 encoded string
19+
DocumentState string `json:"documentState" xml:"documentState" form:"documentState" query:"documentState"`
20+
// *automerge.SyncMessage as base64 encoded string
21+
SyncMessage string `json:"syncMessage" xml:"syncMessage" form:"syncMessage" query:"syncMessage"`
1822
}
1923
)
2024

25+
func (s SyncRequest) GetSyncMessageBytes() ([]byte, error) {
26+
decodedBytes, err := base64.StdEncoding.DecodeString(s.SyncMessage)
27+
if err != nil {
28+
return nil, err
29+
}
30+
return decodedBytes, nil
31+
}
32+
2133
// AutomergeSyncManager manages processing of SyncRequests from clients
2234
type AutomergeSyncManager struct {
2335
treeManager *TreeManager
2436
websocketConnectionManager *WebsocketConnectionManager
2537

2638
// automergeDocuments client connection -> automerge.Doc
27-
automergeDocuments map[*websocket.Conn]string
39+
automergeDocuments map[*websocket.Conn]*automerge.Doc
2840

2941
// lock for synchronizing the tree to the disk
3042
lock mutexSync.RWMutex
@@ -35,7 +47,7 @@ func NewAutomergeSyncManager(
3547
) *AutomergeSyncManager {
3648
s := &AutomergeSyncManager{
3749
treeManager: treeManager,
38-
automergeDocuments: make(map[*websocket.Conn]string),
50+
automergeDocuments: make(map[*websocket.Conn]*automerge.Doc),
3951
}
4052

4153
return s
@@ -59,8 +71,8 @@ func (sm *AutomergeSyncManager) IsItemBeingEditedRecursive(s *Section) (err erro
5971
}
6072

6173
// sets the initial server shadow for a new client connection
62-
func (sm *AutomergeSyncManager) initClient(conn *websocket.Conn, shadowContent string) {
63-
sm.automergeDocuments[conn] = shadowContent
74+
func (sm *AutomergeSyncManager) initClient(conn *websocket.Conn, document *automerge.Doc) {
75+
sm.automergeDocuments[conn] = document
6476
}
6577

6678
// removes the shadow for the given client
@@ -98,19 +110,25 @@ func (sm *AutomergeSyncManager) handleSyncRequest(client *websocket.Conn, syncRe
98110
syncState := automerge.NewSyncState(automergeDocument)
99111
// sm.automergeDocuments[client]
100112

101-
_, err = syncState.ReceiveMessage(syncRequest.SyncState.Bytes())
113+
syncMessageBytes, err := syncRequest.GetSyncMessageBytes()
114+
if err != nil {
115+
log.Printf("%v: error getting sync message bytes: %v", client.RemoteAddr(), err)
116+
return err
117+
}
118+
_, err = syncState.ReceiveMessage(syncMessageBytes)
102119
if err != nil {
103120
log.Printf("%v: error receiving sync state: %v", client.RemoteAddr(), err)
104121
return err
105122
}
106123

124+
// NOTE: this is not needed when using the SyncState API
107125
// apply patches to the automerge document
108-
for _, change := range syncRequest.SyncState.Changes() {
109-
err := automergeDocument.Apply(change)
110-
if err != nil {
111-
return err
112-
}
113-
}
126+
//for _, change := range syncRequest.SyncMessage.Changes() {
127+
// err := automergeDocument.Apply(change)
128+
// if err != nil {
129+
// return err
130+
// }
131+
//}
114132

115133
// then patch the server document version
116134
d := sm.treeManager.GetDocument(documentId)
@@ -121,21 +139,21 @@ func (sm *AutomergeSyncManager) handleSyncRequest(client *websocket.Conn, syncRe
121139
}
122140
d.Content = patchedText
123141

124-
err = sm.sendSyncRequestResponse(client, documentId)
125-
if err != nil {
126-
log.Printf("%v: error sending response: %v", client.RemoteAddr(), err)
127-
return err
128-
}
142+
//err = sm.sendSyncRequestResponse(client, documentId)
143+
//if err != nil {
144+
// log.Printf("%v: error sending response: %v", client.RemoteAddr(), err)
145+
// return err
146+
//}
129147

130148
return err
131149
}
132150

133151
// send the latest document state to the client
134152
func (sm *AutomergeSyncManager) sendInitialTextResponse(client *websocket.Conn, document *Document) (err error) {
135-
// set initial state in backend
136-
sm.initClient(client, document.Content)
153+
automergeDocument, err := sm.getDocument(document.ID)
154+
155+
heads := automergeDocument.Heads()
137156

138-
automergeDocument := automerge.New()
139157
syncState := automerge.NewSyncState(automergeDocument)
140158

141159
documentContentText := automergeDocument.Path("content").Text()
@@ -144,26 +162,34 @@ func (sm *AutomergeSyncManager) sendInitialTextResponse(client *websocket.Conn,
144162
return err
145163
}
146164

147-
commitMessage := "Initial commit"
165+
commitMessage := "Initial Text"
148166
commit, err := automergeDocument.Commit(commitMessage)
149167
log.Printf("Commit: %v", commit)
150168
if err != nil {
151169
return err
152170
}
153171

172+
changes, err := automergeDocument.Changes(heads...)
173+
changes[0].Save()
174+
175+
// set initial state in backend
176+
sm.initClient(client, automergeDocument)
177+
154178
syncStateMessage, valid := syncState.GenerateMessage()
155179
if valid == false {
156180
log.Printf("Error generating sync state message: %v", err)
157181
return err
158182
}
159183

160184
// Write current document state to the client
161-
err = client.WriteJSON(SyncRequest{
162-
Type: TypeInitialContent,
163-
DocumentId: document.ID,
164-
RequestId: "",
165-
SyncState: syncStateMessage,
166-
})
185+
request := SyncRequest{
186+
Type: TypeInitialContent,
187+
DocumentId: document.ID,
188+
RequestId: "",
189+
DocumentState: encodeBase64(automergeDocument.Save()),
190+
SyncMessage: encodeBase64(syncStateMessage.Bytes()),
191+
}
192+
err = client.WriteJSON(request)
167193
if err != nil {
168194
log.Printf("%v: error writing initial content response: %v", client.RemoteAddr(), err)
169195
return err
@@ -172,6 +198,10 @@ func (sm *AutomergeSyncManager) sendInitialTextResponse(client *websocket.Conn,
172198
return
173199
}
174200

201+
func encodeBase64(buffer []byte) string {
202+
return base64.StdEncoding.EncodeToString(buffer)
203+
}
204+
175205
// responds to a client with the changes from the server site document version
176206
func (sm *AutomergeSyncManager) sendSyncRequestResponse(client *websocket.Conn, documentId string) (err error) {
177207
// d := sm.treeManager.GetDocument(documentId)
@@ -192,10 +222,11 @@ func (sm *AutomergeSyncManager) sendSyncRequestResponse(client *websocket.Conn,
192222
return sm.websocketConnectionManager.syncStateToClient(
193223
client,
194224
SyncRequest{
195-
Type: TypeSyncRequest,
196-
RequestId: "",
197-
DocumentId: documentId,
198-
SyncState: syncStateMessage,
225+
Type: TypeSyncRequest,
226+
RequestId: "",
227+
DocumentId: documentId,
228+
DocumentState: encodeBase64(automergeDocument.Save()),
229+
SyncMessage: encodeBase64(syncStateMessage.Bytes()),
199230
})
200231
}
201232

internal/backend/websocket.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package backend
33
import (
44
"fmt"
55
"github.com/gorilla/websocket"
6-
"github.com/labstack/echo/v4"
76
"log"
87
"net/http"
98
mutexSync "sync"
@@ -89,6 +88,7 @@ func (wcm *WebsocketConnectionManager) HandleNewConnection(c echo.Context, docum
8988
}
9089

9190
switch request.(type) {
91+
//case InitialContentRequest:
9292
case EditRequest:
9393
// Send the newly received message to the broadcast channel
9494
err = wcm.handleIncomingMessage(client, request.(EditRequest))
@@ -111,23 +111,45 @@ func (wcm *WebsocketConnectionManager) HandleNewConnection(c echo.Context, docum
111111
return nil
112112
}
113113

114+
type SocketEntityBase struct {
115+
Type string `json:"type" xml:"type" form:"type" query:"type"`
116+
RequestId string `json:"requestId" xml:"requestId" form:"requestId" query:"requestId"`
117+
DocumentId string `json:"documentId" xml:"documentId" form:"documentId" query:"documentId"`
118+
}
119+
114120
func (wcm *WebsocketConnectionManager) parseRequestBody(
115121
client *websocket.Conn,
116122
) (request interface{}, err error) {
117-
var editRequest EditRequest
118-
//Read in a new message as JSON and map it to a Message object
119-
err = client.ReadJSON(&editRequest)
120-
if err != nil {
121-
// try next type
122-
}
123+
var baseRequest SocketEntityBase
123124

124-
var syncRequest SyncRequest
125-
err = client.ReadJSON(&syncRequest)
125+
err = client.ReadJSON(&baseRequest)
126126
if err != nil {
127127
return nil, err
128128
}
129-
130-
return editRequest, nil
129+
switch baseRequest.Type {
130+
case TypeInitialContent:
131+
var initialContentRequest InitialContentRequest
132+
err = client.ReadJSON(&initialContentRequest)
133+
if err != nil {
134+
return nil, err
135+
}
136+
return initialContentRequest, nil
137+
case TypeEditRequest:
138+
var editRequest EditRequest
139+
err = client.ReadJSON(&editRequest)
140+
if err != nil {
141+
return nil, err
142+
}
143+
return editRequest, nil
144+
case TypeSyncRequest:
145+
var syncRequest SyncRequest
146+
err = client.ReadJSON(&syncRequest)
147+
if err != nil {
148+
return nil, err
149+
}
150+
return syncRequest, nil
151+
}
152+
return nil, nil
131153
}
132154

133155
// processes incoming messages from connected clients

0 commit comments

Comments
 (0)