func readMessage(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { connUuid := ps.ByName("conn_uuid") msgId, err := strconv.ParseUint(ps.ByName("msg_uuid"), 10, 64) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // load our msg and status msg, err := store.MsgFromId(connUuid, msgId) defer msg.Release() if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // output it js, err := json.Marshal(msg) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(js) }
// Starts our sender, this starts a goroutine that blocks on receiving a message to send func (t TwitterConnection) Start() { // todo: this doesn't need to happen for each connection anaconda.SetConsumerKey(cfg.Config.Twitter.Consumer_Key) anaconda.SetConsumerSecret(cfg.Config.Twitter.Consumer_Secret) // this is our sending thread go func() { t.wg.Add(1) defer t.wg.Done() var id uint64 // configure our API api := anaconda.NewTwitterApi(t.token, t.secret) defer api.Close() for { // mark ourselves as ready for work, this never blocks t.readySenders <- t // wait for a job to come in, or for us to be shut down select { case id = <-t.pendingMsg: case <-t.done: return } var msgLog = "" // load our msg msg, err := store.MsgFromId(t.connection.Uuid, id) if err != nil { msgLog = fmt.Sprintf("[%s][%d] Error sending msg (%d): %s", t.connection.Uuid, t.id, id, err.Error()) } else { // send the message dm, err := api.PostDMToScreenName(msg.Text, msg.Address) if err != nil { msgLog = fmt.Sprintf("[%s][%d] Error sending msg (%d): %s", t.connection.Uuid, t.id, id, err.Error()) } else { msgLog = fmt.Sprintf("[%s][%d] Sent DM, id: %d", t.connection.Uuid, t.id, dm.Id) } } // mark the message as sent err = msg.MarkSent(msgLog) if err != nil { log.Printf("[%s][%d] Error marking msg sent (%d)", t.connection.Uuid, t.id, id) } else { log.Printf("[%s][%d] Sent msg (%d)", t.connection.Uuid, t.id, id) } // release our message back to the pool msg.Release() } }() // this is our receiving thread go func() { t.wg.Add(1) defer t.wg.Done() api := anaconda.NewTwitterApi(t.token, t.secret) defer api.Close() userStream := api.UserStream(url.Values{}) var event interface{} for { // wait for a twitter event to arrive select { case event = <-userStream.C: case <-t.done: userStream.Interrupt() return } // see if this is a direct message dm, ok := event.(anaconda.DirectMessage) if !ok { continue } // check that this isn't one of our own DM's echoing back at us if t.username == strings.ToLower(dm.SenderScreenName) { continue } log.Printf("[%s][%d] Received DM from %s: %s", t.connection.Uuid, t.id, dm.SenderScreenName, dm.Text) // create a new msg from our DM msg := store.MsgFromText(t.connection.Uuid, dm.SenderScreenName, dm.Text) err := msg.WriteToInbox() if err != nil { log.Printf("[%s][%d] Error saving msg (%d): %s", t.connection.Uuid, t.id, dm.Id, err.Error()) } // pass our message to be received t.incoming <- msg.Id // release our message back to the pool msg.Release() } }() }
// Starts our receiver, this starts a goroutine that blocks on msgs to forward func (r HttpReceiver) Start() { go func() { // tell our wait group we started r.wg.Add(1) // when we exit, tell our wait group we stopped defer r.wg.Done() var id uint64 for { // mark ourselves as ready for work, this never blocks r.readyReceivers <- r // wait for a job to come in, or be marked as complete select { case id = <-r.pendingMsg: case <-r.done: return } // load our msg var msgLog = "" msg, err := store.MsgFromId(r.connection.Uuid, id) if err != nil { msgLog = fmt.Sprintf( "[%s][%d] Error loading msg (%d) from store: %s", r.connection.Uuid, r.id, id, err.Error()) } else { js, err := json.Marshal(msg) if err != nil { msgLog = fmt.Sprintf( "[%s][%d] Error json encoding msg (%d): %s", r.connection.Uuid, r.id, id, err.Error()) } else { // we post our Msg body to our receiver URL req, err := http.NewRequest("POST", r.url, bytes.NewBuffer(js)) req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) if err != nil { msgLog = fmt.Sprintf("[%s][%d] Error posting msg (%d): %s", r.connection.Uuid, r.id, id, err.Error()) } else { buf := new(bytes.Buffer) buf.ReadFrom(resp.Body) body := buf.String() if resp.Status != "200" && resp.Status != "201" { msgLog = fmt.Sprintf("[%s][%d] Error posting msg (%d) received status %s: %s", r.connection.Uuid, r.id, id, resp.Status, body) } else { msgLog = fmt.Sprintf("Status: %s\n\n%s", resp.Status, body) } resp.Body.Close() } } } // mark the message as sent err = msg.MarkHandled(msgLog) log.Printf("[%s][%d] Handled msg (%d)", r.connection.Uuid, r.id, id) if err != nil { log.Println("Error marking msg handled") } // release our msg back to our object pool msg.Release() } }() }