Propagate block changes to all of the cluster nodes in plugin mode (#1213)
Co-authored-by: Jesús Espino <jespinog@gmail.com>
This commit is contained in:
parent
81c475028b
commit
f7946821a0
5 changed files with 99 additions and 19 deletions
|
@ -178,6 +178,10 @@ func (p *Plugin) OnDeactivate() error {
|
||||||
return p.server.Shutdown()
|
return p.server.Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Plugin) OnPluginClusterEvent(_ *plugin.Context, ev mmModel.PluginClusterEvent) {
|
||||||
|
p.wsPluginAdapter.HandleClusterEvent(ev)
|
||||||
|
}
|
||||||
|
|
||||||
// ServeHTTP demonstrates a plugin that handles HTTP requests by greeting the world.
|
// ServeHTTP demonstrates a plugin that handles HTTP requests by greeting the world.
|
||||||
func (p *Plugin) ServeHTTP(_ *plugin.Context, w http.ResponseWriter, r *http.Request) {
|
func (p *Plugin) ServeHTTP(_ *plugin.Context, w http.ResponseWriter, r *http.Request) {
|
||||||
router := p.server.GetRootRouter()
|
router := p.server.GetRootRouter()
|
||||||
|
|
20
server/ws/common.go
Normal file
20
server/ws/common.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package ws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mattermost/focalboard/server/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UpdateMsg is sent on block updates.
|
||||||
|
type UpdateMsg struct {
|
||||||
|
Action string `json:"action"`
|
||||||
|
Block model.Block `json:"block"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebsocketCommand is an incoming command from the client.
|
||||||
|
type WebsocketCommand struct {
|
||||||
|
Action string `json:"action"`
|
||||||
|
WorkspaceID string `json:"workspaceId"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
ReadToken string `json:"readToken"`
|
||||||
|
BlockIDs []string `json:"blockIds"`
|
||||||
|
}
|
|
@ -285,6 +285,30 @@ func (pa *PluginAdapter) getUserIDsForWorkspace(workspaceID string) []string {
|
||||||
return userIDs
|
return userIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sendWorkspaceMessageSkipCluster sends a message to all the users
|
||||||
|
// with a websocket client connected to.
|
||||||
|
func (pa *PluginAdapter) sendWorkspaceMessageSkipCluster(workspaceID string, payload map[string]interface{}) {
|
||||||
|
userIDs := pa.getUserIDsForWorkspace(workspaceID)
|
||||||
|
for _, userID := range userIDs {
|
||||||
|
pa.api.PublishWebSocketEvent(websocketActionUpdateBlock, payload, &mmModel.WebsocketBroadcast{UserId: userID})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendWorkspaceMessage sends and propagates a message that is aimed
|
||||||
|
// for all the users that are subscribed to a given workspace.
|
||||||
|
func (pa *PluginAdapter) sendWorkspaceMessage(workspaceID string, payload map[string]interface{}) {
|
||||||
|
go func() {
|
||||||
|
clusterMessage := &ClusterMessage{
|
||||||
|
WorkspaceID: workspaceID,
|
||||||
|
Payload: payload,
|
||||||
|
}
|
||||||
|
|
||||||
|
pa.sendMessageToCluster("websocket_message", clusterMessage)
|
||||||
|
}()
|
||||||
|
|
||||||
|
pa.sendWorkspaceMessageSkipCluster(workspaceID, payload)
|
||||||
|
}
|
||||||
|
|
||||||
func (pa *PluginAdapter) BroadcastBlockChange(workspaceID string, block model.Block) {
|
func (pa *PluginAdapter) BroadcastBlockChange(workspaceID string, block model.Block) {
|
||||||
pa.api.LogInfo("BroadcastingBlockChange",
|
pa.api.LogInfo("BroadcastingBlockChange",
|
||||||
"workspaceID", workspaceID,
|
"workspaceID", workspaceID,
|
||||||
|
@ -296,10 +320,7 @@ func (pa *PluginAdapter) BroadcastBlockChange(workspaceID string, block model.Bl
|
||||||
Block: block,
|
Block: block,
|
||||||
}
|
}
|
||||||
|
|
||||||
userIDs := pa.getUserIDsForWorkspace(workspaceID)
|
pa.sendWorkspaceMessage(workspaceID, structToMap(message))
|
||||||
for _, userID := range userIDs {
|
|
||||||
pa.api.PublishWebSocketEvent(websocketActionUpdateBlock, structToMap(message), &mmModel.WebsocketBroadcast{UserId: userID})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pa *PluginAdapter) BroadcastBlockDelete(workspaceID, blockID, parentID string) {
|
func (pa *PluginAdapter) BroadcastBlockDelete(workspaceID, blockID, parentID string) {
|
||||||
|
|
50
server/ws/plugin_adapter_cluster.go
Normal file
50
server/ws/plugin_adapter_cluster.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package ws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
mmModel "github.com/mattermost/mattermost-server/v6/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClusterMessage struct {
|
||||||
|
WorkspaceID string
|
||||||
|
Payload map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pa *PluginAdapter) sendMessageToCluster(id string, clusterMessage *ClusterMessage) {
|
||||||
|
b, err := json.Marshal(clusterMessage)
|
||||||
|
if err != nil {
|
||||||
|
pa.api.LogError("couldn't get JSON bytes from cluster message",
|
||||||
|
"id", id,
|
||||||
|
"err", err,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
event := mmModel.PluginClusterEvent{Id: id, Data: b}
|
||||||
|
opts := mmModel.PluginClusterEventSendOptions{
|
||||||
|
SendType: mmModel.PluginClusterEventSendTypeReliable,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := pa.api.PublishPluginClusterEvent(event, opts); err != nil {
|
||||||
|
pa.api.LogError("error publishing cluster event",
|
||||||
|
"id", id,
|
||||||
|
"err", err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pa *PluginAdapter) HandleClusterEvent(ev mmModel.PluginClusterEvent) {
|
||||||
|
pa.api.LogDebug("received cluster event", "id", ev.Id)
|
||||||
|
|
||||||
|
var clusterMessage ClusterMessage
|
||||||
|
if err := json.Unmarshal(ev.Data, &clusterMessage); err != nil {
|
||||||
|
pa.api.LogError("cannot unmarshal cluster message data",
|
||||||
|
"id", ev.Id,
|
||||||
|
"err", err,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pa.sendWorkspaceMessageSkipCluster(clusterMessage.WorkspaceID, clusterMessage.Payload)
|
||||||
|
}
|
|
@ -64,21 +64,6 @@ type Server struct {
|
||||||
logger *mlog.Logger
|
logger *mlog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateMsg is sent on block updates.
|
|
||||||
type UpdateMsg struct {
|
|
||||||
Action string `json:"action"`
|
|
||||||
Block model.Block `json:"block"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// WebsocketCommand is an incoming command from the client.
|
|
||||||
type WebsocketCommand struct {
|
|
||||||
Action string `json:"action"`
|
|
||||||
WorkspaceID string `json:"workspaceId"`
|
|
||||||
Token string `json:"token"`
|
|
||||||
ReadToken string `json:"readToken"`
|
|
||||||
BlockIDs []string `json:"blockIds"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type websocketSession struct {
|
type websocketSession struct {
|
||||||
client *wsClient
|
client *wsClient
|
||||||
userID string
|
userID string
|
||||||
|
|
Loading…
Reference in a new issue