github.com/metaworking/channeld@v0.7.3/pkg/channeld/message.go (about) 1 package channeld 2 3 import ( 4 "strings" 5 6 "github.com/metaworking/channeld/pkg/channeldpb" 7 "github.com/metaworking/channeld/pkg/common" 8 "go.uber.org/zap" 9 ) 10 11 // The context of a message for both sending and receiving 12 type MessageContext struct { 13 MsgType channeldpb.MessageType 14 // The weak-typed Message object popped from the message queue 15 Msg common.Message 16 Broadcast uint32 //channeldpb.BroadcastType 17 StubId uint32 18 // The original channelId in the Packet, could be different from Channel.id. 19 // Used for both send and receive. 20 ChannelId uint32 21 22 // The connection that received the message. Required for BroadcastType_ALL_BUT_SENDER but not for sending. 23 Connection ConnectionInChannel 24 // The channel that handling the message. Not required for sending or broadcasting. 25 Channel *Channel 26 // Internally used for receiving 27 arrivalTime ChannelTime 28 } 29 30 func (ctx *MessageContext) HasConnection() bool { 31 conn, ok := ctx.Connection.(*Connection) 32 return ok && conn != nil && !conn.IsClosing() 33 } 34 35 type MessageHandlerFunc func(ctx MessageContext) 36 type messageMapEntry struct { 37 msg common.Message 38 handler MessageHandlerFunc 39 } 40 41 var MessageMap = map[channeldpb.MessageType]*messageMapEntry{ 42 channeldpb.MessageType_AUTH: {&channeldpb.AuthMessage{}, handleAuth}, 43 channeldpb.MessageType_CREATE_CHANNEL: {&channeldpb.CreateChannelMessage{}, handleCreateChannel}, 44 channeldpb.MessageType_REMOVE_CHANNEL: {&channeldpb.RemoveChannelMessage{}, handleRemoveChannel}, 45 channeldpb.MessageType_LIST_CHANNEL: {&channeldpb.ListChannelMessage{}, handleListChannel}, 46 channeldpb.MessageType_SUB_TO_CHANNEL: {&channeldpb.SubscribedToChannelMessage{}, handleSubToChannel}, 47 channeldpb.MessageType_UNSUB_FROM_CHANNEL: {&channeldpb.UnsubscribedFromChannelMessage{}, handleUnsubFromChannel}, 48 channeldpb.MessageType_CHANNEL_DATA_UPDATE: {&channeldpb.ChannelDataUpdateMessage{}, handleChannelDataUpdate}, 49 channeldpb.MessageType_DISCONNECT: {&channeldpb.DisconnectMessage{}, handleDisconnect}, 50 // CREATE_CHANNEL and CREATE_SPATIAL_CHANNEL shared the same message structure and handler 51 channeldpb.MessageType_CREATE_SPATIAL_CHANNEL: {&channeldpb.CreateChannelMessage{}, handleCreateChannel}, 52 channeldpb.MessageType_QUERY_SPATIAL_CHANNEL: {&channeldpb.QuerySpatialChannelMessage{}, handleQuerySpatialChannel}, 53 channeldpb.MessageType_DEBUG_GET_SPATIAL_REGIONS: {&channeldpb.DebugGetSpatialRegionsMessage{}, handleGetSpatialRegionsMessage}, 54 channeldpb.MessageType_UPDATE_SPATIAL_INTEREST: {&channeldpb.UpdateSpatialInterestMessage{}, handleUpdateSpatialInterest}, 55 channeldpb.MessageType_CREATE_ENTITY_CHANNEL: {&channeldpb.CreateEntityChannelMessage{}, handleCreateEntityChannel}, 56 channeldpb.MessageType_ENTITY_GROUP_ADD: {&channeldpb.AddEntityGroupMessage{}, handleAddEntityGroup}, 57 channeldpb.MessageType_ENTITY_GROUP_REMOVE: {&channeldpb.RemoveEntityGroupMessage{}, handleRemoveEntityGroup}, 58 } 59 60 func RegisterMessageHandler(msgType uint32, msg common.Message, handler MessageHandlerFunc) { 61 MessageMap[channeldpb.MessageType(msgType)] = &messageMapEntry{msg, handler} 62 } 63 64 func handleClientToServerUserMessage(ctx MessageContext) { 65 msg, ok := ctx.Msg.(*channeldpb.ServerForwardMessage) 66 if !ok { 67 ctx.Connection.Logger().Error("message is not a ServerForwardMessage, will not be handled.") 68 return 69 } 70 71 var channelOwnerConnId uint32 = 0 72 if ownerConn := ctx.Channel.GetOwner(); ownerConn != nil && !ownerConn.IsClosing() { 73 ownerConn.Send(ctx) 74 channelOwnerConnId = uint32(ownerConn.Id()) 75 } else if ctx.Broadcast > 0 { 76 if ctx.Channel.enableClientBroadcast { 77 ctx.Channel.Broadcast(ctx) 78 } else { 79 ctx.Connection.Logger().Error("illegal attempt to broadcast message as the channel's client broadcasting is disabled", 80 zap.Uint32("msgType", uint32(ctx.MsgType)), 81 zap.String("channelType", ctx.Channel.channelType.String()), 82 zap.Uint32("channelId", uint32(ctx.Channel.id)), 83 ) 84 return 85 } 86 } else { 87 ctx.Channel.Logger().Error("channel has no owner to forward the user-space messaged", 88 zap.Uint32("msgType", uint32(ctx.MsgType)), 89 zap.Uint32("connId", uint32(ctx.Connection.Id())), 90 ) 91 return 92 } 93 94 if len(msg.Payload) < 128 { 95 ctx.Connection.Logger().Verbose("forward user-space message from client to server", 96 zap.Uint32("msgType", uint32(ctx.MsgType)), 97 zap.Uint32("clientConnId", msg.ClientConnId), 98 zap.Uint32("channelId", uint32(ctx.Channel.id)), 99 zap.Uint32("channelOwner", channelOwnerConnId), 100 zap.Uint32("broadcastType", ctx.Broadcast), 101 zap.Int("payloadSize", len(msg.Payload)), 102 ) 103 } else { 104 ctx.Connection.Logger().Debug("forward user-space message from client to server", 105 zap.Uint32("msgType", uint32(ctx.MsgType)), 106 zap.Uint32("clientConnId", msg.ClientConnId), 107 zap.Uint32("channelId", uint32(ctx.Channel.id)), 108 zap.Uint32("channelOwner", channelOwnerConnId), 109 zap.Uint32("broadcastType", ctx.Broadcast), 110 zap.Int("payloadSize", len(msg.Payload)), 111 ) 112 } 113 } 114 115 func HandleServerToClientUserMessage(ctx MessageContext) { 116 msg, ok := ctx.Msg.(*channeldpb.ServerForwardMessage) 117 if !ok { 118 ctx.Connection.Logger().Error("message is not a ServerForwardMessage, will not be handled.") 119 return 120 } 121 122 if len(msg.Payload) < 128 { 123 ctx.Connection.Logger().Verbose("forward user-space message from server to client/server", 124 zap.Uint32("msgType", uint32(ctx.MsgType)), 125 zap.Uint32("clientConnId", msg.ClientConnId), 126 zap.Uint32("channelId", uint32(ctx.Channel.id)), 127 zap.Uint32("broadcastType", ctx.Broadcast), 128 zap.Int("payloadSize", len(msg.Payload)), 129 ) 130 } else { 131 ctx.Connection.Logger().Debug("forward user-space message from server to client/server", 132 zap.Uint32("msgType", uint32(ctx.MsgType)), 133 zap.Uint32("clientConnId", msg.ClientConnId), 134 zap.Uint32("channelId", uint32(ctx.Channel.id)), 135 zap.Uint32("broadcastType", ctx.Broadcast), 136 zap.Int("payloadSize", len(msg.Payload)), 137 ) 138 139 } 140 141 switch channeldpb.BroadcastType(ctx.Broadcast) { 142 case channeldpb.BroadcastType_NO_BROADCAST: 143 if !ctx.Channel.SendToOwner(ctx) { 144 ctx.Connection.Logger().Error("cannot forward the message as the channel has no owner", 145 zap.Uint32("msgType", uint32(ctx.MsgType)), 146 zap.String("channelType", ctx.Channel.channelType.String()), 147 zap.Uint32("channelId", uint32(ctx.Channel.id)), 148 ) 149 } 150 151 /* 152 case channeldpb.BroadcastType_ALL, channeldpb.BroadcastType_ALL_BUT_SENDER, channeldpb.BroadcastType_ALL_BUT_OWNER, 153 channeldpb.BroadcastType_ALL_BUT_CLIENT, channeldpb.BroadcastType_ALL_BUT_SERVER: 154 ctx.Channel.Broadcast(ctx) 155 */ 156 case channeldpb.BroadcastType_SINGLE_CONNECTION: 157 var conn *Connection = nil 158 if msg.ClientConnId == 0 { 159 // server to server 160 conn = ctx.Channel.GetOwner().(*Connection) 161 } else { 162 // server to client 163 conn = GetConnection(ConnectionId(msg.ClientConnId)) 164 } 165 166 if conn != nil && !conn.IsClosing() { 167 conn.Send(ctx) 168 } else { 169 ctx.Connection.Logger().Info("drop the forward message as the target connection does not exist", 170 zap.Uint32("msgType", uint32(ctx.MsgType)), 171 zap.Uint32("targetConnId", msg.ClientConnId), 172 ) 173 } 174 175 default: 176 if ctx.Broadcast >= uint32(channeldpb.BroadcastType_ALL) && ctx.Broadcast < uint32(channeldpb.BroadcastType_ADJACENT_CHANNELS) { 177 ctx.Channel.Broadcast(ctx) 178 } else if channeldpb.BroadcastType_ADJACENT_CHANNELS.Check(ctx.Broadcast) { 179 if ctx.Channel.channelType != channeldpb.ChannelType_SPATIAL { 180 ctx.Connection.Logger().Warn("BroadcastType_ADJACENT_CHANNELS only works for Spatial channel") 181 return 182 } 183 if spatialController == nil { 184 ctx.Connection.Logger().Error("spatial controller doesn't exist") 185 return 186 } 187 channelIds, err := spatialController.GetAdjacentChannels(ctx.Channel.id) 188 if err != nil { 189 ctx.Connection.Logger().Error("failed to retrieve spatial regions", zap.Error(err)) 190 return 191 } 192 // Add the connections in the owner(center) channel? 193 if !channeldpb.BroadcastType_ALL_BUT_OWNER.Check(ctx.Broadcast) { 194 channelIds = append(channelIds, ctx.Channel.id) 195 } 196 197 // Merge all connection in the adjacent channels to one map, to avoid duplicate send. 198 adjacentConns := make(map[ConnectionInChannel]struct{}) 199 for _, id := range channelIds { 200 channel := GetChannel(id) 201 if channel == nil { 202 ctx.Connection.Logger().Error("invalid channel id for broadcast", zap.Uint32("channelId", uint32(id))) 203 continue 204 } 205 conns := channel.GetAllConnections() 206 for conn := range conns { 207 adjacentConns[conn] = struct{}{} 208 } 209 } 210 for conn := range adjacentConns { 211 // Ignore the sender? 212 if channeldpb.BroadcastType_ALL_BUT_SENDER.Check(ctx.Broadcast) && conn == ctx.Connection { 213 continue 214 } 215 // Ignore the clients? 216 if channeldpb.BroadcastType_ALL_BUT_CLIENT.Check(ctx.Broadcast) && conn.GetConnectionType() == channeldpb.ConnectionType_CLIENT { 217 continue 218 } 219 // Ignore the servers? 220 if channeldpb.BroadcastType_ALL_BUT_SERVER.Check(ctx.Broadcast) && conn.GetConnectionType() == channeldpb.ConnectionType_SERVER { 221 continue 222 } 223 // Ignore the client specified in the ServerForwardMessage 224 if conn.Id() == ConnectionId(msg.ClientConnId) { 225 continue 226 } 227 conn.Send(ctx) 228 } 229 } 230 } 231 } 232 233 func handleAuth(ctx MessageContext) { 234 if ctx.Channel != globalChannel { 235 ctx.Connection.Logger().Error("illegal attemp to authenticate outside the GLOBAL channel") 236 ctx.Connection.Close() 237 return 238 } 239 msg, ok := ctx.Msg.(*channeldpb.AuthMessage) 240 if !ok { 241 ctx.Connection.Logger().Error("mssage is not an AuthMessage, will not be handled.") 242 ctx.Connection.Close() 243 return 244 } 245 //log.Printf("Auth PIT: %s, LT: %s\n", msg.PlayerIdentifierToken, msg.LoginToken) 246 247 _, banned := pitBlacklist[msg.PlayerIdentifierToken] 248 if banned { 249 securityLogger.Info("refused authentication of banned PIT", zap.String("pit", msg.PlayerIdentifierToken)) 250 ctx.Connection.Close() 251 return 252 } 253 254 if authProvider == nil && !GlobalSettings.Development { 255 rootLogger.Panic("no auth provider") 256 return 257 } 258 259 authResult := channeldpb.AuthResultMessage_SUCCESSFUL 260 if ctx.Connection.GetConnectionType() == channeldpb.ConnectionType_SERVER && GlobalSettings.ServerBypassAuth { 261 onAuthComplete(ctx, authResult, msg.PlayerIdentifierToken) 262 } else if authProvider != nil { 263 go func() { 264 authResult, err := authProvider.DoAuth(ctx.Connection.Id(), msg.PlayerIdentifierToken, msg.LoginToken) 265 if err != nil { 266 ctx.Connection.Logger().Error("failed to do auth", zap.Error(err)) 267 ctx.Connection.Close() 268 } else { 269 onAuthComplete(ctx, authResult, msg.PlayerIdentifierToken) 270 } 271 }() 272 } else { 273 onAuthComplete(ctx, authResult, msg.PlayerIdentifierToken) 274 } 275 } 276 277 func onAuthComplete(ctx MessageContext, authResult channeldpb.AuthResultMessage_AuthResult, pit string) { 278 if ctx.Connection.IsClosing() { 279 return 280 } 281 282 if authResult == channeldpb.AuthResultMessage_SUCCESSFUL { 283 ctx.Connection.OnAuthenticated(pit) 284 } 285 286 ctx.Msg = &channeldpb.AuthResultMessage{ 287 Result: authResult, 288 ConnId: uint32(ctx.Connection.Id()), 289 CompressionType: GlobalSettings.CompressionType, 290 } 291 ctx.Connection.Send(ctx) 292 293 // Also send the respond to The GLOBAL channel owner (to handle the client's subscription if it doesn't have the authority to). 294 if globalChannel.HasOwner() { 295 ctx.StubId = 0 296 globalChannel.SendToOwner(ctx) 297 } 298 299 Event_AuthComplete.Broadcast(AuthEventData{ 300 AuthResult: authResult, 301 Connection: ctx.Connection, 302 PlayerIdentifierToken: pit, 303 }) 304 } 305 306 func handleCreateChannel(ctx MessageContext) { 307 // Only the GLOBAL channel can handle channel creation/deletion/listing 308 if ctx.Channel != globalChannel { 309 ctx.Connection.Logger().Error("illegal attemp to create channel outside the GLOBAL channel") 310 return 311 } 312 313 msg, ok := ctx.Msg.(*channeldpb.CreateChannelMessage) 314 if !ok { 315 ctx.Connection.Logger().Error("message is not a CreateChannelMessage, will not be handled.") 316 return 317 } 318 319 var newChannel *Channel 320 var err error 321 if msg.ChannelType == channeldpb.ChannelType_UNKNOWN { 322 ctx.Connection.Logger().Error("illegal attemp to create the UNKNOWN channel") 323 return 324 } else if msg.ChannelType == channeldpb.ChannelType_GLOBAL { 325 // Global channel is initially created by the system. Creating the channel will attempt to own it. 326 newChannel = globalChannel 327 if !globalChannel.HasOwner() { 328 globalChannel.SetOwner(ctx.Connection) 329 Event_GlobalChannelPossessed.Broadcast(globalChannel) 330 ctx.Connection.Logger().Info("owned the GLOBAL channel") 331 } else { 332 ctx.Connection.Logger().Error("illegal attemp to create the GLOBAL channel") 333 return 334 } 335 } else if msg.ChannelType == channeldpb.ChannelType_SPATIAL { 336 handleCreateSpatialChannel(ctx, msg) 337 return 338 } else { 339 newChannel, err = CreateChannel(msg.ChannelType, ctx.Connection) 340 if err != nil { 341 ctx.Connection.Logger().Error("failed to create channel", 342 zap.Uint32("channelType", uint32(msg.ChannelType)), 343 zap.Error(err), 344 ) 345 return 346 } 347 newChannel.Logger().Info("created channel with owner", zap.Uint32("ownerConnId", uint32(newChannel.GetOwner().Id()))) 348 } 349 350 newChannel.metadata = msg.Metadata 351 if msg.Data != nil { 352 dataMsg, err := msg.Data.UnmarshalNew() 353 if err != nil { 354 newChannel.Logger().Error("failed to unmarshal data message for the new channel", zap.Error(err)) 355 return 356 } else { 357 newChannel.InitData(dataMsg, msg.MergeOptions) 358 } 359 } else { 360 // Channel data should always be initialized 361 newChannel.InitData(nil, msg.MergeOptions) 362 } 363 364 ctx.Msg = &channeldpb.CreateChannelResultMessage{ 365 ChannelType: newChannel.channelType, 366 Metadata: newChannel.metadata, 367 OwnerConnId: uint32(ctx.Connection.Id()), 368 ChannelId: uint32(newChannel.id), 369 } 370 ctx.Connection.Send(ctx) 371 // Also send the response to the GLOBAL channel owner. 372 if globalChannel.GetOwner() != ctx.Connection && globalChannel.HasOwner() { 373 ctx.StubId = 0 374 globalChannel.SendToOwner(ctx) 375 } 376 377 // Subscribe to channel after creation 378 cs, _ := ctx.Connection.SubscribeToChannel(newChannel, msg.SubOptions) 379 if cs != nil { 380 ctx.Connection.sendSubscribed(ctx, newChannel, ctx.Connection, 0, &cs.options) 381 } 382 } 383 384 func handleRemoveChannel(ctx MessageContext) { 385 386 msg, ok := ctx.Msg.(*channeldpb.RemoveChannelMessage) 387 if !ok { 388 ctx.Connection.Logger().Error("message is not a RemoveChannelMessage, will not be handled.") 389 return 390 } 391 392 channelToRemove := GetChannel(common.ChannelId(msg.ChannelId)) 393 if channelToRemove == nil { 394 ctx.Connection.Logger().Error("invalid channelId for removing", zap.Uint32("channelId", msg.ChannelId)) 395 return 396 } 397 398 // Check ACL from settings 399 // If ctx.Connection == nil, the removal is triggered internally (e.g. ChannelSettings.RemoveChannelAfterOwnerRemoved) 400 hasAccess, err := channelToRemove.CheckACL(ctx.Connection, ChannelAccessType_Remove) 401 if ctx.HasConnection() && !hasAccess { 402 ownerConnId := uint32(0) 403 if channelToRemove.HasOwner() { 404 ownerConnId = uint32(channelToRemove.GetOwner().Id()) 405 } 406 ctx.Connection.Logger().Error("connection doesn't have access to remove channel", 407 zap.String("channelType", channelToRemove.channelType.String()), 408 zap.Uint32("channelId", uint32(channelToRemove.id)), 409 zap.Uint32("ownerConnId", ownerConnId), 410 zap.Error(err)) 411 return 412 } 413 414 for sc := range channelToRemove.subscribedConnections { 415 if sc != nil { 416 //sc.sendUnsubscribed(ctx, channelToRemove, 0) 417 response := ctx 418 response.StubId = 0 419 sc.Send(response) 420 } 421 } 422 RemoveChannel(channelToRemove) 423 424 var logger *Logger 425 if ctx.HasConnection() { 426 logger = ctx.Connection.Logger() 427 } else { 428 logger = RootLogger() 429 } 430 logger.Info("removed channel", 431 zap.String("channelType", channelToRemove.channelType.String()), 432 zap.Uint32("channelId", uint32(channelToRemove.id)), 433 zap.Int("subs", len(channelToRemove.subscribedConnections)), 434 ) 435 } 436 437 func handleListChannel(ctx MessageContext) { 438 if ctx.Channel != globalChannel { 439 ctx.Connection.Logger().Error("illegal attemp to list channel outside the GLOBAL channel") 440 return 441 } 442 443 msg, ok := ctx.Msg.(*channeldpb.ListChannelMessage) 444 if !ok { 445 ctx.Connection.Logger().Error("message is not a ListChannelMessage, will not be handled.") 446 return 447 } 448 449 result := make([]*channeldpb.ListChannelResultMessage_ChannelInfo, 0) 450 allChannels.Range(func(_ common.ChannelId, channel *Channel) bool { 451 if msg.TypeFilter != channeldpb.ChannelType_UNKNOWN && msg.TypeFilter != channel.channelType { 452 return true 453 } 454 matched := len(msg.MetadataFilters) == 0 455 for _, keyword := range msg.MetadataFilters { 456 if strings.Contains(channel.metadata, keyword) { 457 matched = true 458 break 459 } 460 } 461 if matched { 462 result = append(result, &channeldpb.ListChannelResultMessage_ChannelInfo{ 463 ChannelId: uint32(channel.id), 464 ChannelType: channel.channelType, 465 Metadata: channel.metadata, 466 }) 467 } 468 return true 469 }) 470 471 ctx.Msg = &channeldpb.ListChannelResultMessage{ 472 Channels: result, 473 } 474 ctx.Connection.Send(ctx) 475 } 476 477 func handleSubToChannel(ctx MessageContext) { 478 msg, ok := ctx.Msg.(*channeldpb.SubscribedToChannelMessage) 479 if !ok { 480 ctx.Connection.Logger().Error("message is not a SubscribedToChannelMessage, will not be handled.") 481 return 482 } 483 484 var connToSub *Connection 485 if ctx.Connection.GetConnectionType() == channeldpb.ConnectionType_CLIENT { 486 connToSub = ctx.Connection.(*Connection) 487 } else { 488 // Only the server can specify a ConnId. 489 connToSub = GetConnection(ConnectionId(msg.ConnId)) 490 } 491 492 if connToSub == nil { 493 ctx.Connection.Logger().Error("invalid ConnectionId for sub", zap.Uint32("connIdInMsg", msg.ConnId)) 494 return 495 } 496 497 hasAccess, err := ctx.Channel.CheckACL(ctx.Connection, ChannelAccessType_Sub) 498 if connToSub.Id() != ctx.Connection.Id() && !hasAccess { 499 ctx.Connection.Logger().Warn("connection doesn't have access to sub connection to this channel", 500 zap.Uint32("subConnId", msg.ConnId), 501 zap.String("channelType", ctx.Channel.channelType.String()), 502 zap.Uint32("channelId", uint32(ctx.Channel.id)), 503 zap.Error(err), 504 ) 505 return 506 } 507 508 /* 509 cs, exists := ctx.Channel.subscribedConnections[connToSub] 510 if exists { 511 ctx.Connection.Logger().Debug("already subscribed to channel, the subscription options will be merged", 512 zap.String("channelType", ctx.Channel.channelType.String()), 513 zap.Uint32("channelId", uint32(ctx.Channel.id)), 514 ) 515 if msg.SubOptions != nil { 516 proto.Merge(&cs.options, msg.SubOptions) 517 } 518 connToSub.sendSubscribed(ctx, ctx.Channel, connToSub, 0, &cs.options) 519 // Do not send the SubscribedToChannelResultMessage to the sender or channel owner if already subed. 520 return 521 } 522 */ 523 524 cs, shouldSend := connToSub.SubscribeToChannel(ctx.Channel, msg.SubOptions) 525 if !shouldSend { 526 return 527 } 528 529 // Always notify the sender - may need to update the sub options. 530 ctx.Connection.sendSubscribed(ctx, ctx.Channel, connToSub, ctx.StubId, &cs.options) 531 532 // Notify the subscribed if it's not the sender. 533 if connToSub != ctx.Connection { 534 connToSub.sendSubscribed(ctx, ctx.Channel, connToSub, 0, &cs.options) 535 } 536 537 // Notify the channel owner if not already subed and it's not the sender. 538 if ownerConn := ctx.Channel.GetOwner(); ownerConn != nil && ownerConn != ctx.Connection && !ownerConn.IsClosing() { 539 ownerConn.sendSubscribed(ctx, ctx.Channel, connToSub, 0, &cs.options) 540 } 541 } 542 543 func handleUnsubFromChannel(ctx MessageContext) { 544 msg, ok := ctx.Msg.(*channeldpb.UnsubscribedFromChannelMessage) 545 if !ok { 546 ctx.Connection.Logger().Error("message is not a UnsubscribedFromChannelMessage, will not be handled.") 547 return 548 } 549 550 // The connection that unsubscribes. Could be different to the connection that sends the message. 551 connToUnsub := GetConnection(ConnectionId(msg.ConnId)) 552 if connToUnsub == nil { 553 ctx.Connection.Logger().Error("invalid ConnectionId for unsub", zap.Uint32("connId", msg.ConnId)) 554 return 555 } 556 557 hasAccess, accessErr := ctx.Channel.CheckACL(ctx.Connection, ChannelAccessType_Unsub) 558 if connToUnsub.id != ctx.Connection.Id() && !hasAccess { 559 ctx.Connection.Logger().Error("connection dosen't have access to unsub connection from this channel", 560 zap.Uint32("unsubConnId", msg.ConnId), 561 zap.String("channelType", ctx.Channel.channelType.String()), 562 zap.Uint32("channelId", uint32(ctx.Channel.id)), 563 zap.Error(accessErr), 564 ) 565 return 566 } 567 568 _, err := connToUnsub.UnsubscribeFromChannel(ctx.Channel) 569 if err != nil { 570 ctx.Connection.Logger().Warn("failed to unsub from channel", 571 zap.String("channelType", ctx.Channel.channelType.String()), 572 zap.Uint32("channelId", uint32(ctx.Channel.id)), 573 zap.Error(err), 574 ) 575 return 576 } 577 578 // Notify the sender. 579 ctx.Connection.sendUnsubscribed(ctx, ctx.Channel, connToUnsub, ctx.StubId) 580 581 // Notify the unsubscribed. 582 if connToUnsub != ctx.Connection { 583 connToUnsub.sendUnsubscribed(ctx, ctx.Channel, connToUnsub, 0) 584 } 585 // Notify the channel owner. 586 if ownerConn := ctx.Channel.GetOwner(); ownerConn != nil && !ownerConn.IsClosing() { 587 if ownerConn != ctx.Connection && ownerConn != connToUnsub { 588 ownerConn.sendUnsubscribed(ctx, ctx.Channel, connToUnsub, 0) 589 } else if ownerConn == connToUnsub { 590 // Reset the owner if it unsubscribed itself 591 ctx.Channel.SetOwner(nil) 592 } 593 } 594 } 595 596 func handleChannelDataUpdate(ctx MessageContext) { 597 // Only channel owner or writable subsciptors can update the data 598 if ownerConn := ctx.Channel.GetOwner(); ownerConn != ctx.Connection { 599 cs := ctx.Channel.subscribedConnections[ctx.Connection] 600 if cs == nil || *cs.options.DataAccess != channeldpb.ChannelDataAccess_WRITE_ACCESS { 601 if ctx.Connection.GetConnectionType() == channeldpb.ConnectionType_SERVER && ownerConn != nil && !ownerConn.IsClosing() { 602 // Quick fix: set the sender to the channel owner if it's a server connection 603 ctx.Connection = ownerConn 604 } else { 605 ctx.Connection.Logger().Warn("attempt to update channel data but has no access", 606 zap.String("channelType", ctx.Channel.channelType.String()), 607 zap.Uint32("channelId", uint32(ctx.Channel.id)), 608 ) 609 return 610 } 611 } 612 } 613 614 if ctx.Channel.Data() == nil { 615 ctx.Channel.Logger().Info("channel data is not initialized - should send CreateChannelMessage before ChannelDataUpdateMessage", 616 zap.Uint32("connId", uint32(ctx.Connection.Id()))) 617 return 618 } 619 620 msg, ok := ctx.Msg.(*channeldpb.ChannelDataUpdateMessage) 621 if !ok { 622 ctx.Connection.Logger().Error("message is not a ChannelDataUpdateMessage, will not be handled.") 623 return 624 } 625 updateMsg, err := msg.Data.UnmarshalNew() 626 if err != nil { 627 ctx.Connection.Logger().Error("failed to unmarshal channel update data", zap.Error(err), 628 zap.String("channelType", ctx.Channel.channelType.String()), 629 zap.String("typeUrl", msg.Data.TypeUrl)) 630 return 631 } 632 633 if ctx.Channel.spatialNotifier != nil { 634 if ctx.Connection.GetConnectionType() == channeldpb.ConnectionType_CLIENT { 635 ctx.Channel.SetDataUpdateConnId(ctx.Connection.Id()) 636 } else { 637 ctx.Channel.SetDataUpdateConnId(ConnectionId(msg.ContextConnId)) 638 } 639 } 640 ctx.Channel.Data().OnUpdate(updateMsg, ctx.arrivalTime, ctx.Connection.Id(), ctx.Channel.spatialNotifier) 641 } 642 643 func handleDisconnect(ctx MessageContext) { 644 if ctx.Channel != globalChannel { 645 ctx.Connection.Logger().Error("illegal attemp to disconnect another connection outside the GLOBAL channel") 646 return 647 } 648 649 msg, ok := ctx.Msg.(*channeldpb.DisconnectMessage) 650 if !ok { 651 ctx.Connection.Logger().Error("message is not a DisconnectMessage, will not be handled.") 652 return 653 } 654 655 connToDisconnect := GetConnection(ConnectionId(msg.ConnId)) 656 if connToDisconnect == nil { 657 ctx.Connection.Logger().Warn("could not find the connection to disconnect", 658 zap.Uint32("targetConnId", msg.ConnId), 659 ) 660 return 661 } 662 663 if err := connToDisconnect.Disconnect(); err != nil { 664 ctx.Connection.Logger().Warn("failed to disconnect a connection", 665 zap.Uint32("targetConnId", msg.ConnId), 666 zap.String("targetConnType", connToDisconnect.connectionType.String()), 667 ) 668 } else { 669 ctx.Connection.Logger().Info("successfully disconnected a connection", 670 zap.Uint32("targetConnId", msg.ConnId), 671 zap.String("targetConnType", connToDisconnect.connectionType.String()), 672 ) 673 } 674 connToDisconnect.Close() 675 }