Download this file
| 1 | package hub |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "errors" |
| 6 | ) |
| 7 | |
| 8 | // ErrNotFanout is a Fanout of a type that is targeted or server-raised. |
| 9 | var ErrNotFanout = errors.New("hub: not a fan-out type") |
| 10 | |
| 11 | // Fanout is §4.3's chat and share: an admitted peer to every other |
| 12 | // admitted peer, the envelope rebuilt from the sender's participation so |
| 13 | // from and name can never be forged, nothing ringed or stored (§6). |
| 14 | // The sender's authority is §2.5's last row, exactly as Relay's: a |
| 15 | // member-kind participation re-derives standing first (§15.12), and one |
| 16 | // whose standing is gone is ended here with lost{standing} and answered |
| 17 | // ErrNotYours; a guest never consults standing at all (ruling 14). |
| 18 | func (h *Hub) Fanout(ctx context.Context, sqid, session string, from PeerID, m Message) error { |
| 19 | if m.Type != TypeChat && m.Type != TypeShare { |
| 20 | return ErrNotFanout |
| 21 | } |
| 22 | gone, err := h.memberStandingGone(ctx, sqid, session, from, true) |
| 23 | if err != nil { |
| 24 | return err |
| 25 | } |
| 26 | if gone { |
| 27 | return ErrNotYours |
| 28 | } |
| 29 | h.mu.Lock() |
| 30 | defer h.mu.Unlock() |
| 31 | r, ok := h.rooms[sqid] |
| 32 | if !ok { |
| 33 | return ErrUnknownPeer |
| 34 | } |
| 35 | p, found := h.findLocked(sqid, session, from) |
| 36 | if !found { |
| 37 | return ErrUnknownPeer |
| 38 | } |
| 39 | if !p.Admitted { |
| 40 | return ErrNotAdmitted |
| 41 | } |
| 42 | out := Message{Type: m.Type, From: p.Peer, Name: p.Name, Payload: m.Payload} |
| 43 | h.broadcastLocked(r, out, func(q *Participation) bool { return q.Admitted && q.Peer != p.Peer }) |
| 44 | return nil |
| 45 | } |
| 46 | |