Re: Longpoll with Libsoup



Hi,

in former versions of the libsoup it was enough just to poll the underlying socket from time to time. On SOUP_SOCKET_ERROR it was finishing the messages itself. Now, a little bit more code is needed. Here is how I solved it in C++:

For each incoming request install a poll on the underlying socket. Also hold a set of all messages received on a specific socket. Whenever reading from the socket results in SOUP_SOCKET_EOF or SOUP_SOCKET_ERROR, call soup_message_finished on the associated messages.

namespace SOCKET_POLL
{
  typedef set<SoupMessage*> tRecordSet;
  map<SoupSocket*, tRecordSet> s_socketToMessages;

  gboolean pollSocket(SoupSocket *socket)
  {
    char buffer;
    gsize len = 0;

SoupSocketIOStatus result = soup_socket_read (socket, &buffer, 1, &len, NULL, NULL);

    if(result == SOUP_SOCKET_EOF || result == SOUP_SOCKET_ERROR)
    {
      tRecordSet &s = s_socketToMessages[socket];
      tRecordSet localCopy;
      swap(s, localCopy);

      for(SoupMessage* msg : localCopy)
      {
        soup_message_finished(msg);
      }

      soup_socket_disconnect(socket);

      s_socketToMessages.erase(socket);

      return FALSE;
    }

    return TRUE;
  }

  void removePoll(guint pollerTimer, SoupSocket *socket)
  {
    g_source_remove(pollerTimer);
    s_socketToMessages.erase(socket);
  }

  void msg_finished(SoupMessage *msg, SoupSocket *socket)
  {
    auto sIT = s_socketToMessages.find(socket);

    if(sIT != s_socketToMessages.end())
    {
      tRecordSet &s = sIT->second;
      auto msgIT = s.find(msg);

      if(msgIT != s.end())
      {
        s.erase(msgIT);

        if(s.empty())
        {
          s_socketToMessages.erase(sIT);
        }
      }
    }
  }

void installSocketPoll(SoupServer *server, SoupMessage *msg, SoupSocket *socket)
  {
    if(s_socketToMessages.find(socket) == s_socketToMessages.end())
    {
guint poller = g_timeout_add_seconds(30, (GSourceFunc)pollSocket, socket); g_object_weak_ref((GObject*)socket, (GWeakNotify)removePoll, (void*)poller);
    }

    s_socketToMessages[socket].insert(msg);

    g_signal_connect(msg, "finished", (GCallback)&msg_finished, socket);
  }
}

void Server::serverCallback (SoupServer *server, SoupMessage *msg, const char *strPath, GHashTable *query, SoupClientContext *context, Server *pThis)
{
SOCKET_POLL::installSocketPoll(server, msg, soup_client_context_get_socket(context));
  .....
}

Best, Henry



Am 13.05.2012, 20:04 Uhr, schrieb Christian Hergert <chris dronelabs com>:

Hi,

I have a similar question to Mark's post about longpolling a few weeks
ago. I have a system that is doing lonpolling. However, I would like to
stop various backend work when the client disconnects. I haven't found a
way to get an event upon the client disconnecting.

What I've tried:

  Create a server, tried both sync and async w/ mainloop.
  Handle incoming request, pause message to simulate longpoll.
  Attach to various signals on the message's SoupSocket such as:
    - disconnect
    - event
  Get the raw FD for the socket w/ soup_socket_get_fd().
  Create a new GSource that poll's for (G_IO_ERR | G_IO_HUP) on FD.

It appears based on the code I've read that "disconnect" would be
unlikely to fire while the SoupMessage's IO is paused. (That is why I
tried the route of polling the FD myself with a custom GSource and
g_source_add_poll().

Anyway, still no luck as those poll conditions don't seem to fire.

For the client, I tried both curl and telnet w/ ^]quit.

Thanks for libsoup, it's fantastic.

-- Christian

_______________________________________________
libsoup-list mailing list
libsoup-list gnome org
http://mail.gnome.org/mailman/listinfo/libsoup-list



--
Erstellt mit Operas revolutionärem E-Mail-Modul: http://www.opera.com/mail/


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]