mirror of
https://github.com/strukturag/nextcloud-spreed-signaling
synced 2026-03-14 14:35:44 +01:00
Merge pull request #1185 from strukturag/multiple-chat-comments
Support receiving and forwarding multiple chat messages from Talk.
This commit is contained in:
commit
cb6df05cd3
5 changed files with 433 additions and 136 deletions
|
|
@ -1215,6 +1215,14 @@ type RoomEventMessageDataChat struct {
|
|||
|
||||
// Comment will be included if the client supports the "chat-relay" feature.
|
||||
Comment json.RawMessage `json:"comment,omitempty"`
|
||||
// Comments will be included if the client supports the "chat-relay" feature.
|
||||
Comments []json.RawMessage `json:"comments,omitempty"`
|
||||
}
|
||||
|
||||
func (m *RoomEventMessageDataChat) HasComment() bool {
|
||||
return len(m.Comment) > 0 || slices.ContainsFunc(m.Comments, func(comment json.RawMessage) bool {
|
||||
return len(comment) > 0
|
||||
})
|
||||
}
|
||||
|
||||
type RoomEventMessageData struct {
|
||||
|
|
|
|||
|
|
@ -1396,6 +1396,35 @@ func easyjson6128dd2DecodeGithubComStrukturagNextcloudSpreedSignalingApi9(in *jl
|
|||
in.AddError((out.Comment).UnmarshalJSON(data))
|
||||
}
|
||||
}
|
||||
case "comments":
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
out.Comments = nil
|
||||
} else {
|
||||
in.Delim('[')
|
||||
if out.Comments == nil {
|
||||
if !in.IsDelim(']') {
|
||||
out.Comments = make([]json.RawMessage, 0, 2)
|
||||
} else {
|
||||
out.Comments = []json.RawMessage{}
|
||||
}
|
||||
} else {
|
||||
out.Comments = (out.Comments)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v16 json.RawMessage
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
} else {
|
||||
if data := in.Raw(); in.Ok() {
|
||||
in.AddError((v16).UnmarshalJSON(data))
|
||||
}
|
||||
}
|
||||
out.Comments = append(out.Comments, v16)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
}
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
|
|
@ -1426,6 +1455,25 @@ func easyjson6128dd2EncodeGithubComStrukturagNextcloudSpreedSignalingApi9(out *j
|
|||
}
|
||||
out.Raw((in.Comment).MarshalJSON())
|
||||
}
|
||||
if len(in.Comments) != 0 {
|
||||
const prefix string = ",\"comments\":"
|
||||
if first {
|
||||
first = false
|
||||
out.RawString(prefix[1:])
|
||||
} else {
|
||||
out.RawString(prefix)
|
||||
}
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v17, v18 := range in.Comments {
|
||||
if v17 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.Raw((v18).MarshalJSON())
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
|
||||
|
|
@ -1749,33 +1797,33 @@ func easyjson6128dd2DecodeGithubComStrukturagNextcloudSpreedSignalingApi13(in *j
|
|||
out.Changed = (out.Changed)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v16 StringMap
|
||||
var v19 StringMap
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
} else {
|
||||
in.Delim('{')
|
||||
if !in.IsDelim('}') {
|
||||
v16 = make(StringMap)
|
||||
v19 = make(StringMap)
|
||||
} else {
|
||||
v16 = nil
|
||||
v19 = nil
|
||||
}
|
||||
for !in.IsDelim('}') {
|
||||
key := string(in.String())
|
||||
in.WantColon()
|
||||
var v17 interface{}
|
||||
if m, ok := v17.(easyjson.Unmarshaler); ok {
|
||||
var v20 interface{}
|
||||
if m, ok := v20.(easyjson.Unmarshaler); ok {
|
||||
m.UnmarshalEasyJSON(in)
|
||||
} else if m, ok := v17.(json.Unmarshaler); ok {
|
||||
} else if m, ok := v20.(json.Unmarshaler); ok {
|
||||
_ = m.UnmarshalJSON(in.Raw())
|
||||
} else {
|
||||
v17 = in.Interface()
|
||||
v20 = in.Interface()
|
||||
}
|
||||
(v16)[key] = v17
|
||||
(v19)[key] = v20
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
}
|
||||
out.Changed = append(out.Changed, v16)
|
||||
out.Changed = append(out.Changed, v19)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
|
|
@ -1796,33 +1844,33 @@ func easyjson6128dd2DecodeGithubComStrukturagNextcloudSpreedSignalingApi13(in *j
|
|||
out.Users = (out.Users)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v18 StringMap
|
||||
var v21 StringMap
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
} else {
|
||||
in.Delim('{')
|
||||
if !in.IsDelim('}') {
|
||||
v18 = make(StringMap)
|
||||
v21 = make(StringMap)
|
||||
} else {
|
||||
v18 = nil
|
||||
v21 = nil
|
||||
}
|
||||
for !in.IsDelim('}') {
|
||||
key := string(in.String())
|
||||
in.WantColon()
|
||||
var v19 interface{}
|
||||
if m, ok := v19.(easyjson.Unmarshaler); ok {
|
||||
var v22 interface{}
|
||||
if m, ok := v22.(easyjson.Unmarshaler); ok {
|
||||
m.UnmarshalEasyJSON(in)
|
||||
} else if m, ok := v19.(json.Unmarshaler); ok {
|
||||
} else if m, ok := v22.(json.Unmarshaler); ok {
|
||||
_ = m.UnmarshalJSON(in.Raw())
|
||||
} else {
|
||||
v19 = in.Interface()
|
||||
v22 = in.Interface()
|
||||
}
|
||||
(v18)[key] = v19
|
||||
(v21)[key] = v22
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
}
|
||||
out.Users = append(out.Users, v18)
|
||||
out.Users = append(out.Users, v21)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
|
|
@ -1872,43 +1920,7 @@ func easyjson6128dd2EncodeGithubComStrukturagNextcloudSpreedSignalingApi13(out *
|
|||
out.RawString(prefix)
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v20, v21 := range in.Changed {
|
||||
if v20 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
if v21 == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 {
|
||||
out.RawString(`null`)
|
||||
} else {
|
||||
out.RawByte('{')
|
||||
v22First := true
|
||||
for v22Name, v22Value := range v21 {
|
||||
if v22First {
|
||||
v22First = false
|
||||
} else {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v22Name))
|
||||
out.RawByte(':')
|
||||
if m, ok := v22Value.(easyjson.Marshaler); ok {
|
||||
m.MarshalEasyJSON(out)
|
||||
} else if m, ok := v22Value.(json.Marshaler); ok {
|
||||
out.Raw(m.MarshalJSON())
|
||||
} else {
|
||||
out.Raw(json.Marshal(v22Value))
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
if len(in.Users) != 0 {
|
||||
const prefix string = ",\"users\":"
|
||||
out.RawString(prefix)
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v23, v24 := range in.Users {
|
||||
for v23, v24 := range in.Changed {
|
||||
if v23 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
|
|
@ -1939,6 +1951,42 @@ func easyjson6128dd2EncodeGithubComStrukturagNextcloudSpreedSignalingApi13(out *
|
|||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
if len(in.Users) != 0 {
|
||||
const prefix string = ",\"users\":"
|
||||
out.RawString(prefix)
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v26, v27 := range in.Users {
|
||||
if v26 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
if v27 == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 {
|
||||
out.RawString(`null`)
|
||||
} else {
|
||||
out.RawByte('{')
|
||||
v28First := true
|
||||
for v28Name, v28Value := range v27 {
|
||||
if v28First {
|
||||
v28First = false
|
||||
} else {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v28Name))
|
||||
out.RawByte(':')
|
||||
if m, ok := v28Value.(easyjson.Marshaler); ok {
|
||||
m.MarshalEasyJSON(out)
|
||||
} else if m, ok := v28Value.(json.Marshaler); ok {
|
||||
out.Raw(m.MarshalJSON())
|
||||
} else {
|
||||
out.Raw(json.Marshal(v28Value))
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
}
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
}
|
||||
if in.All {
|
||||
const prefix string = ",\"all\":"
|
||||
out.RawString(prefix)
|
||||
|
|
@ -2623,15 +2671,15 @@ func easyjson6128dd2DecodeGithubComStrukturagNextcloudSpreedSignalingApi21(in *j
|
|||
for !in.IsDelim('}') {
|
||||
key := string(in.String())
|
||||
in.WantColon()
|
||||
var v26 interface{}
|
||||
if m, ok := v26.(easyjson.Unmarshaler); ok {
|
||||
var v29 interface{}
|
||||
if m, ok := v29.(easyjson.Unmarshaler); ok {
|
||||
m.UnmarshalEasyJSON(in)
|
||||
} else if m, ok := v26.(json.Unmarshaler); ok {
|
||||
} else if m, ok := v29.(json.Unmarshaler); ok {
|
||||
_ = m.UnmarshalJSON(in.Raw())
|
||||
} else {
|
||||
v26 = in.Interface()
|
||||
v29 = in.Interface()
|
||||
}
|
||||
(out.Payload)[key] = v26
|
||||
(out.Payload)[key] = v29
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
|
|
@ -2702,21 +2750,21 @@ func easyjson6128dd2EncodeGithubComStrukturagNextcloudSpreedSignalingApi21(out *
|
|||
out.RawString(`null`)
|
||||
} else {
|
||||
out.RawByte('{')
|
||||
v27First := true
|
||||
for v27Name, v27Value := range in.Payload {
|
||||
if v27First {
|
||||
v27First = false
|
||||
v30First := true
|
||||
for v30Name, v30Value := range in.Payload {
|
||||
if v30First {
|
||||
v30First = false
|
||||
} else {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v27Name))
|
||||
out.String(string(v30Name))
|
||||
out.RawByte(':')
|
||||
if m, ok := v27Value.(easyjson.Marshaler); ok {
|
||||
if m, ok := v30Value.(easyjson.Marshaler); ok {
|
||||
m.MarshalEasyJSON(out)
|
||||
} else if m, ok := v27Value.(json.Marshaler); ok {
|
||||
} else if m, ok := v30Value.(json.Marshaler); ok {
|
||||
out.Raw(m.MarshalJSON())
|
||||
} else {
|
||||
out.Raw(json.Marshal(v27Value))
|
||||
out.Raw(json.Marshal(v30Value))
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
|
|
@ -3868,13 +3916,13 @@ func easyjson6128dd2DecodeGithubComStrukturagNextcloudSpreedSignalingApi32(in *j
|
|||
out.Features = (out.Features)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v28 string
|
||||
var v31 string
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
} else {
|
||||
v28 = string(in.String())
|
||||
v31 = string(in.String())
|
||||
}
|
||||
out.Features = append(out.Features, v28)
|
||||
out.Features = append(out.Features, v31)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
|
|
@ -3922,11 +3970,11 @@ func easyjson6128dd2EncodeGithubComStrukturagNextcloudSpreedSignalingApi32(out *
|
|||
out.RawString(prefix)
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v29, v30 := range in.Features {
|
||||
if v29 > 0 {
|
||||
for v32, v33 := range in.Features {
|
||||
if v32 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v30))
|
||||
out.String(string(v33))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
|
|
@ -4359,13 +4407,13 @@ func easyjson6128dd2DecodeGithubComStrukturagNextcloudSpreedSignalingApi36(in *j
|
|||
out.Features = (out.Features)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v31 string
|
||||
var v34 string
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
} else {
|
||||
v31 = string(in.String())
|
||||
v34 = string(in.String())
|
||||
}
|
||||
out.Features = append(out.Features, v31)
|
||||
out.Features = append(out.Features, v34)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
|
|
@ -4419,11 +4467,11 @@ func easyjson6128dd2EncodeGithubComStrukturagNextcloudSpreedSignalingApi36(out *
|
|||
out.RawString(prefix)
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v32, v33 := range in.Features {
|
||||
if v32 > 0 {
|
||||
for v35, v36 := range in.Features {
|
||||
if v35 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v33))
|
||||
out.String(string(v36))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
|
|
@ -4511,13 +4559,13 @@ func easyjson6128dd2DecodeGithubComStrukturagNextcloudSpreedSignalingApi37(in *j
|
|||
out.Join = (out.Join)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v34 EventServerMessageSessionEntry
|
||||
var v37 EventServerMessageSessionEntry
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
} else {
|
||||
(v34).UnmarshalEasyJSON(in)
|
||||
(v37).UnmarshalEasyJSON(in)
|
||||
}
|
||||
out.Join = append(out.Join, v34)
|
||||
out.Join = append(out.Join, v37)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
|
|
@ -4538,13 +4586,13 @@ func easyjson6128dd2DecodeGithubComStrukturagNextcloudSpreedSignalingApi37(in *j
|
|||
out.Leave = (out.Leave)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v35 PublicSessionId
|
||||
var v38 PublicSessionId
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
} else {
|
||||
v35 = PublicSessionId(in.String())
|
||||
v38 = PublicSessionId(in.String())
|
||||
}
|
||||
out.Leave = append(out.Leave, v35)
|
||||
out.Leave = append(out.Leave, v38)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
|
|
@ -4565,13 +4613,13 @@ func easyjson6128dd2DecodeGithubComStrukturagNextcloudSpreedSignalingApi37(in *j
|
|||
out.Change = (out.Change)[:0]
|
||||
}
|
||||
for !in.IsDelim(']') {
|
||||
var v36 EventServerMessageSessionEntry
|
||||
var v39 EventServerMessageSessionEntry
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
} else {
|
||||
(v36).UnmarshalEasyJSON(in)
|
||||
(v39).UnmarshalEasyJSON(in)
|
||||
}
|
||||
out.Change = append(out.Change, v36)
|
||||
out.Change = append(out.Change, v39)
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim(']')
|
||||
|
|
@ -4703,11 +4751,11 @@ func easyjson6128dd2EncodeGithubComStrukturagNextcloudSpreedSignalingApi37(out *
|
|||
out.RawString(prefix)
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v37, v38 := range in.Join {
|
||||
if v37 > 0 {
|
||||
for v40, v41 := range in.Join {
|
||||
if v40 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
(v38).MarshalEasyJSON(out)
|
||||
(v41).MarshalEasyJSON(out)
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
|
|
@ -4717,11 +4765,11 @@ func easyjson6128dd2EncodeGithubComStrukturagNextcloudSpreedSignalingApi37(out *
|
|||
out.RawString(prefix)
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v39, v40 := range in.Leave {
|
||||
if v39 > 0 {
|
||||
for v42, v43 := range in.Leave {
|
||||
if v42 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v40))
|
||||
out.String(string(v43))
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
|
|
@ -4731,11 +4779,11 @@ func easyjson6128dd2EncodeGithubComStrukturagNextcloudSpreedSignalingApi37(out *
|
|||
out.RawString(prefix)
|
||||
{
|
||||
out.RawByte('[')
|
||||
for v41, v42 := range in.Change {
|
||||
if v41 > 0 {
|
||||
for v44, v45 := range in.Change {
|
||||
if v44 > 0 {
|
||||
out.RawByte(',')
|
||||
}
|
||||
(v42).MarshalEasyJSON(out)
|
||||
(v45).MarshalEasyJSON(out)
|
||||
}
|
||||
out.RawByte(']')
|
||||
}
|
||||
|
|
@ -5844,15 +5892,15 @@ func easyjson6128dd2DecodeGithubComStrukturagNextcloudSpreedSignalingApi48(in *j
|
|||
for !in.IsDelim('}') {
|
||||
key := string(in.String())
|
||||
in.WantColon()
|
||||
var v43 interface{}
|
||||
if m, ok := v43.(easyjson.Unmarshaler); ok {
|
||||
var v46 interface{}
|
||||
if m, ok := v46.(easyjson.Unmarshaler); ok {
|
||||
m.UnmarshalEasyJSON(in)
|
||||
} else if m, ok := v43.(json.Unmarshaler); ok {
|
||||
} else if m, ok := v46.(json.Unmarshaler); ok {
|
||||
_ = m.UnmarshalJSON(in.Raw())
|
||||
} else {
|
||||
v43 = in.Interface()
|
||||
v46 = in.Interface()
|
||||
}
|
||||
(out.Payload)[key] = v43
|
||||
(out.Payload)[key] = v46
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
|
|
@ -5904,21 +5952,21 @@ func easyjson6128dd2EncodeGithubComStrukturagNextcloudSpreedSignalingApi48(out *
|
|||
out.RawString(`null`)
|
||||
} else {
|
||||
out.RawByte('{')
|
||||
v44First := true
|
||||
for v44Name, v44Value := range in.Payload {
|
||||
if v44First {
|
||||
v44First = false
|
||||
v47First := true
|
||||
for v47Name, v47Value := range in.Payload {
|
||||
if v47First {
|
||||
v47First = false
|
||||
} else {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(v44Name))
|
||||
out.String(string(v47Name))
|
||||
out.RawByte(':')
|
||||
if m, ok := v44Value.(easyjson.Marshaler); ok {
|
||||
if m, ok := v47Value.(easyjson.Marshaler); ok {
|
||||
m.MarshalEasyJSON(out)
|
||||
} else if m, ok := v44Value.(json.Marshaler); ok {
|
||||
} else if m, ok := v47Value.(json.Marshaler); ok {
|
||||
out.Raw(m.MarshalJSON())
|
||||
} else {
|
||||
out.Raw(json.Marshal(v44Value))
|
||||
out.Raw(json.Marshal(v47Value))
|
||||
}
|
||||
}
|
||||
out.RawByte('}')
|
||||
|
|
|
|||
|
|
@ -1867,6 +1867,36 @@ Message format (Backend -> Server)
|
|||
}
|
||||
|
||||
|
||||
The signaling server also supports combining multiple chat comments into one
|
||||
request which will then be sent out individually to clients.
|
||||
|
||||
Message format (Backend -> Server)
|
||||
|
||||
{
|
||||
"type": "message"
|
||||
"message" {
|
||||
"data": {
|
||||
"type": "chat",
|
||||
"chat": {
|
||||
"refresh": true,
|
||||
"comments": [
|
||||
{
|
||||
...properties of the first comment written in the chat...
|
||||
},
|
||||
{
|
||||
...properties of the second comment written in the chat...
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
In this case, clients will either receive a single `"refresh": true` message
|
||||
(if they don't support `chat-relay`) or multiple messages with the different
|
||||
comments.
|
||||
|
||||
|
||||
### Notify sessions to switch to a different room
|
||||
|
||||
This can be used to let sessions in a room know that they switch to a different
|
||||
|
|
|
|||
|
|
@ -721,15 +721,14 @@ func (s *ClientSession) sendCandidate(client sfu.Client, sender api.PublicSessio
|
|||
}
|
||||
|
||||
// +checklocks:s.mu
|
||||
func (s *ClientSession) sendMessageUnlocked(message *api.ServerMessage) bool {
|
||||
func (s *ClientSession) sendMessageUnlocked(message *api.ServerMessage) {
|
||||
if c := s.getClientUnlocked(); c != nil {
|
||||
if c.SendMessage(message) {
|
||||
return true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
s.storePendingMessage(message)
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *ClientSession) SendError(e *api.Error) bool {
|
||||
|
|
@ -741,15 +740,21 @@ func (s *ClientSession) SendError(e *api.Error) bool {
|
|||
}
|
||||
|
||||
func (s *ClientSession) SendMessage(message *api.ServerMessage) bool {
|
||||
message = s.filterMessage(message)
|
||||
if message == nil {
|
||||
message, messages := s.filterMessage(message)
|
||||
if message == nil && len(messages) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return s.sendMessageUnlocked(message)
|
||||
if message != nil {
|
||||
s.sendMessageUnlocked(message)
|
||||
}
|
||||
for _, msg := range messages {
|
||||
s.sendMessageUnlocked(msg)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *ClientSession) SendMessages(messages []*api.ServerMessage) bool {
|
||||
|
|
@ -1333,7 +1338,7 @@ func (s *ClientSession) filterDuplicateFlags(message *api.RoomFlagsServerMessage
|
|||
return false
|
||||
}
|
||||
|
||||
func (s *ClientSession) filterMessage(message *api.ServerMessage) *api.ServerMessage {
|
||||
func (s *ClientSession) filterMessage(message *api.ServerMessage) (*api.ServerMessage, []*api.ServerMessage) {
|
||||
switch message.Type {
|
||||
case "event":
|
||||
switch message.Event.Target {
|
||||
|
|
@ -1356,7 +1361,7 @@ func (s *ClientSession) filterMessage(message *api.ServerMessage) *api.ServerMes
|
|||
m.Changed = nil
|
||||
case "flags":
|
||||
if s.filterDuplicateFlags(message.Event.Flags) {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
case "room":
|
||||
|
|
@ -1364,7 +1369,7 @@ func (s *ClientSession) filterMessage(message *api.ServerMessage) *api.ServerMes
|
|||
case "join":
|
||||
join := s.filterDuplicateJoin(message.Event.Join)
|
||||
if len(join) == 0 {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
copied := false
|
||||
if len(join) != len(message.Event.Join) {
|
||||
|
|
@ -1402,7 +1407,7 @@ func (s *ClientSession) filterMessage(message *api.ServerMessage) *api.ServerMes
|
|||
|
||||
leave := s.filterUnknownLeave(message.Event.Leave)
|
||||
if len(leave) == 0 {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for _, e := range message.Event.Leave {
|
||||
|
|
@ -1423,57 +1428,104 @@ func (s *ClientSession) filterMessage(message *api.ServerMessage) *api.ServerMes
|
|||
}
|
||||
case "message":
|
||||
if message.Event.Message == nil || len(message.Event.Message.Data) == 0 {
|
||||
return message
|
||||
return message, nil
|
||||
}
|
||||
|
||||
data, err := message.Event.Message.GetData()
|
||||
if data == nil || err != nil {
|
||||
return message
|
||||
return message, nil
|
||||
}
|
||||
|
||||
if data.Type == "chat" && data.Chat != nil {
|
||||
update := false
|
||||
if data.Chat.Refresh && len(data.Chat.Comment) > 0 {
|
||||
if data.Chat.Refresh && data.Chat.HasComment() {
|
||||
// New-style chat event, check what the client supports.
|
||||
if s.HasFeature(api.ClientFeatureChatRelay) {
|
||||
data.Chat.Refresh = false
|
||||
} else {
|
||||
data.Chat.Comment = nil
|
||||
data.Chat.Comments = nil
|
||||
}
|
||||
update = true
|
||||
}
|
||||
|
||||
if len(data.Chat.Comment) > 0 && s.HasPermission(api.PERMISSION_HIDE_DISPLAYNAMES) {
|
||||
var comment api.ChatComment
|
||||
if err := json.Unmarshal(data.Chat.Comment, &comment); err != nil {
|
||||
return message
|
||||
}
|
||||
|
||||
if displayName, found := comment["actorDisplayName"]; found && displayName != "" {
|
||||
comment["actorDisplayName"] = ""
|
||||
var err error
|
||||
if data.Chat.Comment, err = json.Marshal(comment); err != nil {
|
||||
return message
|
||||
if data.Chat.HasComment() {
|
||||
data.Chat.Comments = slices.DeleteFunc(data.Chat.Comments, func(comment json.RawMessage) bool {
|
||||
return len(comment) == 0
|
||||
})
|
||||
if len(data.Chat.Comment) > 0 {
|
||||
if len(data.Chat.Comments) == 0 {
|
||||
data.Chat.Comments = []json.RawMessage{data.Chat.Comment}
|
||||
} else {
|
||||
data.Chat.Comments = append([]json.RawMessage{data.Chat.Comment}, data.Chat.Comments...)
|
||||
}
|
||||
data.Chat.Comment = nil
|
||||
}
|
||||
if len(data.Chat.Comments) > 0 && s.HasPermission(api.PERMISSION_HIDE_DISPLAYNAMES) {
|
||||
for i, commentData := range data.Chat.Comments {
|
||||
var comment api.ChatComment
|
||||
if err := json.Unmarshal(commentData, &comment); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if displayName, found := comment["actorDisplayName"]; found && displayName != "" {
|
||||
comment["actorDisplayName"] = ""
|
||||
var err error
|
||||
if commentData, err = json.Marshal(comment); err != nil {
|
||||
continue
|
||||
}
|
||||
data.Chat.Comments[i] = commentData
|
||||
update = true
|
||||
}
|
||||
}
|
||||
update = true
|
||||
}
|
||||
}
|
||||
|
||||
if update {
|
||||
if encoded, err := json.Marshal(data); err == nil {
|
||||
// Create unique copy of message for only this client.
|
||||
message = &api.ServerMessage{
|
||||
Id: message.Id,
|
||||
Type: message.Type,
|
||||
Event: &api.EventServerMessage{
|
||||
Type: message.Event.Type,
|
||||
Target: message.Event.Target,
|
||||
Message: &api.RoomEventMessage{
|
||||
RoomId: message.Event.Message.RoomId,
|
||||
Data: encoded,
|
||||
if update || len(data.Chat.Comments) > 0 {
|
||||
if len(data.Chat.Comment) == 0 && len(data.Chat.Comments) == 0 {
|
||||
if encoded, err := json.Marshal(data); err == nil {
|
||||
// Create unique copy of message for only this client.
|
||||
message = &api.ServerMessage{
|
||||
Id: message.Id,
|
||||
Type: message.Type,
|
||||
Event: &api.EventServerMessage{
|
||||
Type: message.Event.Type,
|
||||
Target: message.Event.Target,
|
||||
Message: &api.RoomEventMessage{
|
||||
RoomId: message.Event.Message.RoomId,
|
||||
Data: encoded,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Forward different chat comments individually.
|
||||
var result []*api.ServerMessage
|
||||
for _, comment := range data.Chat.Comments {
|
||||
commentData := api.RoomEventMessageData{
|
||||
Type: data.Type,
|
||||
Chat: &api.RoomEventMessageDataChat{
|
||||
Refresh: data.Chat.Refresh,
|
||||
Comment: comment,
|
||||
},
|
||||
}
|
||||
if encoded, err := json.Marshal(commentData); err == nil {
|
||||
// Create unique copy of message for only this client.
|
||||
result = append(result, &api.ServerMessage{
|
||||
Id: message.Id,
|
||||
Type: message.Type,
|
||||
Event: &api.EventServerMessage{
|
||||
Type: message.Event.Type,
|
||||
Target: message.Event.Target,
|
||||
Message: &api.RoomEventMessage{
|
||||
RoomId: message.Event.Message.RoomId,
|
||||
Data: encoded,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil, result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1483,16 +1535,16 @@ func (s *ClientSession) filterMessage(message *api.ServerMessage) *api.ServerMes
|
|||
if message.Message != nil && len(message.Message.Data) > 0 && s.HasPermission(api.PERMISSION_HIDE_DISPLAYNAMES) {
|
||||
var data api.MessageServerMessageData
|
||||
if err := json.Unmarshal(message.Message.Data, &data); err != nil {
|
||||
return message
|
||||
return message, nil
|
||||
}
|
||||
|
||||
if data.Type == "nickChanged" {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return message
|
||||
return message, nil
|
||||
}
|
||||
|
||||
func (s *ClientSession) filterAsyncMessage(msg *events.AsyncMessage) *api.ServerMessage {
|
||||
|
|
|
|||
|
|
@ -249,6 +249,72 @@ func TestFeatureChatRelay(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
chatComment2 := api.StringMap{
|
||||
"hello": "world",
|
||||
}
|
||||
message2 := api.StringMap{
|
||||
"type": "chat",
|
||||
"chat": api.StringMap{
|
||||
"refresh": true,
|
||||
"comments": []api.StringMap{
|
||||
chatComment,
|
||||
chatComment2,
|
||||
},
|
||||
},
|
||||
}
|
||||
data2, err := json.Marshal(message2)
|
||||
require.NoError(err)
|
||||
|
||||
// Simulate request from the backend.
|
||||
room.processAsyncMessage(&events.AsyncMessage{
|
||||
Type: "room",
|
||||
Room: &talk.BackendServerRoomRequest{
|
||||
Type: "message",
|
||||
Message: &talk.BackendRoomMessageRequest{
|
||||
Data: data2,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if msg, ok := client.RunUntilRoomMessage(ctx); ok {
|
||||
assert.Equal(roomId, msg.RoomId)
|
||||
var data api.StringMap
|
||||
if err := json.Unmarshal(msg.Data, &data); assert.NoError(err) {
|
||||
assert.Equal("chat", data["type"], "invalid type entry in %+v", data)
|
||||
if chat, found := api.GetStringMapEntry[map[string]any](data, "chat"); assert.True(found, "chat entry is missing in %+v", data) {
|
||||
if feature {
|
||||
assert.EqualValues(chatComment, chat["comment"])
|
||||
_, found := chat["refresh"]
|
||||
assert.False(found, "refresh should not be included")
|
||||
|
||||
// A second message with the second comment will be sent
|
||||
if msg, ok := client.RunUntilRoomMessage(ctx); ok {
|
||||
assert.Equal(roomId, msg.RoomId)
|
||||
|
||||
if err := json.Unmarshal(msg.Data, &data); assert.NoError(err) {
|
||||
assert.Equal("chat", data["type"], "invalid type entry in %+v", data)
|
||||
if chat, found := api.GetStringMapEntry[map[string]any](data, "chat"); assert.True(found, "chat entry is missing in %+v", data) {
|
||||
assert.EqualValues(chatComment2, chat["comment"])
|
||||
_, found := chat["refresh"]
|
||||
assert.False(found, "refresh should not be included")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Only a single refresh will be sent
|
||||
assert.Equal(true, chat["refresh"])
|
||||
_, found := chat["comment"]
|
||||
assert.False(found, "the comment should not be included")
|
||||
|
||||
ctx2, cancel2 := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
||||
defer cancel2()
|
||||
|
||||
client.RunUntilErrorIs(ctx2, context.DeadlineExceeded)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -461,6 +527,99 @@ func TestFeatureChatRelayFederation(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
chatComment2 := api.StringMap{
|
||||
"hello": "world",
|
||||
}
|
||||
message2 := api.StringMap{
|
||||
"type": "chat",
|
||||
"chat": api.StringMap{
|
||||
"refresh": true,
|
||||
"comments": []api.StringMap{
|
||||
chatComment,
|
||||
chatComment2,
|
||||
},
|
||||
},
|
||||
}
|
||||
data2, err := json.Marshal(message2)
|
||||
require.NoError(err)
|
||||
|
||||
// Simulate request from the backend.
|
||||
room.processAsyncMessage(&events.AsyncMessage{
|
||||
Type: "room",
|
||||
Room: &talk.BackendServerRoomRequest{
|
||||
Type: "message",
|
||||
Message: &talk.BackendRoomMessageRequest{
|
||||
Data: data2,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// The first client will receive the message for the local room (always including the actual message).
|
||||
if msg, ok := client1.RunUntilRoomMessage(ctx); ok {
|
||||
assert.Equal(roomId, msg.RoomId)
|
||||
var data api.StringMap
|
||||
if err := json.Unmarshal(msg.Data, &data); assert.NoError(err) {
|
||||
assert.Equal("chat", data["type"], "invalid type entry in %+v", data)
|
||||
if chat, found := api.GetStringMapEntry[map[string]any](data, "chat"); assert.True(found, "chat entry is missing in %+v", data) {
|
||||
AssertEqualSerialized(t, chatComment, chat["comment"])
|
||||
_, found := chat["refresh"]
|
||||
assert.False(found, "refresh should not be included")
|
||||
}
|
||||
}
|
||||
}
|
||||
// A second message with the second comment will be sent
|
||||
if msg, ok := client1.RunUntilRoomMessage(ctx); ok {
|
||||
assert.Equal(roomId, msg.RoomId)
|
||||
var data api.StringMap
|
||||
if err := json.Unmarshal(msg.Data, &data); assert.NoError(err) {
|
||||
assert.Equal("chat", data["type"], "invalid type entry in %+v", data)
|
||||
if chat, found := api.GetStringMapEntry[map[string]any](data, "chat"); assert.True(found, "chat entry is missing in %+v", data) {
|
||||
assert.EqualValues(chatComment2, chat["comment"])
|
||||
_, found := chat["refresh"]
|
||||
assert.False(found, "refresh should not be included")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The second client will receive the message from the federated room (either as refresh or with the message).
|
||||
if msg, ok := client2.RunUntilRoomMessage(ctx); ok {
|
||||
assert.Equal(federatedRoomId, msg.RoomId)
|
||||
var data api.StringMap
|
||||
if err := json.Unmarshal(msg.Data, &data); assert.NoError(err) {
|
||||
assert.Equal("chat", data["type"], "invalid type entry in %+v", data)
|
||||
if chat, found := api.GetStringMapEntry[map[string]any](data, "chat"); assert.True(found, "chat entry is missing in %+v", data) {
|
||||
if feature {
|
||||
AssertEqualSerialized(t, federatedChatComment, chat["comment"])
|
||||
_, found := chat["refresh"]
|
||||
assert.False(found, "refresh should not be included")
|
||||
|
||||
// A second message with the second comment will be sent
|
||||
if msg, ok := client2.RunUntilRoomMessage(ctx); ok {
|
||||
assert.Equal(federatedRoomId, msg.RoomId)
|
||||
if err := json.Unmarshal(msg.Data, &data); assert.NoError(err) {
|
||||
assert.Equal("chat", data["type"], "invalid type entry in %+v", data)
|
||||
if chat, found := api.GetStringMapEntry[map[string]any](data, "chat"); assert.True(found, "chat entry is missing in %+v", data) {
|
||||
assert.EqualValues(chatComment2, chat["comment"])
|
||||
_, found := chat["refresh"]
|
||||
assert.False(found, "refresh should not be included")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Only a single refresh will be sent
|
||||
assert.Equal(true, chat["refresh"])
|
||||
_, found := chat["comment"]
|
||||
assert.False(found, "the comment should not be included")
|
||||
|
||||
ctx2, cancel2 := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
||||
defer cancel2()
|
||||
|
||||
client2.RunUntilErrorIs(ctx2, context.DeadlineExceeded)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue