(hub *Hub)
| 115 | } |
| 116 | |
| 117 | func (t *Topic) run(hub *Hub) { |
| 118 | |
| 119 | log.Printf("Topic started: '%s'", t.name) |
| 120 | |
| 121 | keepAlive := time.Second * 5 // TODO(gene): read keepalive value from the command line |
| 122 | killTimer := time.NewTimer(time.Hour) |
| 123 | killTimer.Stop() |
| 124 | |
| 125 | for { |
| 126 | select { |
| 127 | case sreg := <-t.reg: |
| 128 | // Request to add a conection to this topic |
| 129 | |
| 130 | // The topic is alive, so stop the kill timer, if it's ticking. We don't want the topic to die |
| 131 | // while processing the call |
| 132 | killTimer.Stop() |
| 133 | |
| 134 | if err := t.handleSubscription(hub, sreg); err == nil { |
| 135 | // give a broadcast channel to the connection (.read) |
| 136 | // give channel to use when shutting down (.done) |
| 137 | sreg.sess.subs[t.name] = &Subscription{broadcast: t.broadcast, done: t.unreg, meta: t.meta} |
| 138 | t.sessions[sreg.sess] = true |
| 139 | |
| 140 | } else if len(t.sessions) == 0 { |
| 141 | // Failed to subscribe, the topic is still inactive |
| 142 | killTimer.Reset(keepAlive) |
| 143 | } |
| 144 | case leave := <-t.unreg: |
| 145 | // Remove connection from topic; session may continue to function |
| 146 | delete(t.sessions, leave.sess) |
| 147 | |
| 148 | now := time.Now().UTC().Round(time.Millisecond) |
| 149 | pud := t.perUser[leave.sess.uid] |
| 150 | if pud.lastSeenTag == nil { |
| 151 | pud.lastSeenTag = map[string]time.Time{} |
| 152 | } |
| 153 | pud.lastSeenTag[leave.sess.tag] = now |
| 154 | t.perUser[leave.sess.uid] = pud |
| 155 | if err := store.Topics.UpdateLastSeen(t.appid, t.name, leave.sess.uid, leave.sess.tag, now); err != nil { |
| 156 | log.Println(err) |
| 157 | } |
| 158 | |
| 159 | // User wants to unsubscribe. |
| 160 | if leave.unsub { |
| 161 | // Delete user's subscription from the database |
| 162 | if err := store.Subs.Delete(t.appid, t.name, leave.sess.uid); err != nil { |
| 163 | if leave.pkt != nil { |
| 164 | leave.sess.QueueOut(ErrUnknown(leave.pkt.Leave.Id, leave.pkt.Leave.Topic, now)) |
| 165 | } |
| 166 | log.Println(err) |
| 167 | continue |
| 168 | } |
| 169 | |
| 170 | // Delete per-user data |
| 171 | delete(t.perUser, leave.sess.uid) |
| 172 | |
| 173 | // Detach all user's sessions |
| 174 | for sess, _ := range t.sessions { |
no test coverage detected