0

"Using socket.io, I would like to broadcast a message sent by the user only to a subset of all clients. The subset would lie within a certain distance of the user emitting the message (say 1km). It seems I would need to add something like this (http://stackoverflow.com/questions/27928/how-do-i-calculate-distance-between-two-latitude-longitude-points) to the [socket.on 'broadcast', (message)] section of the code below (please note this is coffeescript and pulled from Shoaib Burq's geochat-example github repo (https://github.com/sabman/geochat-example))."

Now including Ricardo's suggestions, replacing the old [socket.on 'broadcast', (message) ->] section with his input (although I changed "user" to "record" to stay consistent with the rest of the server.coffee code), and the [find:] section at the end. Something is wrong, though, and I'm not sure if it has to do with the html code or the updates to the coffeescript. Thanks again in advance..

Code still isn't running. Including Ricardo's newest suggestions:

 socket.on 'broadcast', (message) ->
    # find the sender and extract it's position
    Character.find { clientId: socket.id }, (record) =>
        chat_data =
            user: record
            conversation: message
        [lat, lng] = record.geometry.coordinates
        # find everyone within a 1km square
        km = 1/111
         area = 
            type: 'Polygon'
            coordinates: [
               [lat - km, lng - km]
               [lat + km, lng - km]
               [lat + km, lng + km]
               [lat - km, lng + km]
            ]
        Character.find { within: area }, (record) ->
            // send message to each user

     socket.broadcast.send JSON.stringify(chat_data)

I have a feeling the problem may lie with the 'find' section. For instance, Ricardo wrote

    console.log ">> find #{JSON.stringify(attrs)}"

But in the original code, this reads with a "=>" instead of ">>":

    console.log "=> find #{JSON.stringify(attrs)}"

qs = require 'querystring'

find: (query, callback) ->
    console.log ">> find #{JSON.stringify(attrs)}"

    q = { operator: "or",  properties: attrs }
    url = lyr_config_characters.api_url
    key = lyr_config_characters.acl.get

    if query.id?
      url += "/#{attrs.id}?" + qs.stringify({ key })
    else if query.within?
      url += "/functions/within?" + qs.stringify({ key, input : query.within })
    else
      url += qs.stringify { key, input: q }

    req =
        method: "GET"
        uri: url
        headers: { "Content-Type": "application/json" }

    request req, (error, response, body) ->
        console.log error if error
        console.log "<< find #{body}"
        callback JSON.parse body ? '{}'

Thank you!

po.studio
  • 4,007
  • 5
  • 25
  • 37
  • Thanks, Ricardo. The rest of the code is here: https://github.com/sabman/geochat-example/blob/master/server.coffee – po.studio Apr 12 '12 at 20:58

1 Answers1

0

The example you are using is based on spatialdb, which seems to have very incomplete documentation.

From the looks of it, you need to query users using a geometry object, it will return points (users) that are contained within:

socket.on 'broadcast', (message) ->
    # find the sender and extract it's position
    Character.find { clientId: socket.id }, (user) ->
        chat_data =
            user: user
            conversation: message
        [lat, lng] = user.geometry.coordinates
        # find everyone within a 1km square
        km = 1/111
        area = 
            type: 'Polygon'
            coordinates: [
               [lat - km, lng - km]
               [lat + km, lng - km]
               [lat + km, lng + km]
               [lat - km, lng + km]
            ]
        Character.find { within: area }, (users) ->
            // send message to each user

You'll also need to modify the find method to use the within query:

find: (attrs, callback) ->
    console.log "=> find #{JSON.stringify(attrs)}"
    q = { operator: "or",  properties: attrs }
    if _.contains(_.keys(attrs), "id")
      url = "#{lyr_config_characters.api_url}/#{attrs.id}?key=#{lyr_config_characters.acl.get}"
    else if _.contains(_.keys(attrs), "within")
      url = "#{lyr_config_characters.api_url}/functions/within?key=#{lyr_config_characters.acl.get}&input=#{encodeURIComponent(JSON.stringify(attrs.within))}"
    else
      url = "#{lyr_config_characters.api_url}?key=#{lyr_config_characters.acl.get}&input=#{encodeURIComponent(JSON.stringify(q))}"
    req = { method: "GET", uri: url, headers: {"Content-Type": "application/json"} }

(which, for sanity, I would rewrite)

qs = require 'querystring'

find: (query, callback) ->
    console.log ">> find #{JSON.stringify(attrs)}"

    q = { operator: "or",  properties: attrs }
    url = lyr_config_characters.api_url
    key = lyr_config_characters.acl.get

    if query.id?
      url += "/#{attrs.id}?" + qs.stringify({ key })
    else if query.within?
      url += "/functions/within?" + qs.stringify({ key, input : query.within })
    else
      url += qs.stringify { key, input: q }

    req =
        method: "GET"
        uri: url
        headers: { "Content-Type": "application/json" }

    request req, (error, response, body) ->
        console.log error if error
        console.log "<< find #{body}"
        callback JSON.parse body ? '{}'
Ricardo Tomasi
  • 34,573
  • 2
  • 55
  • 66
  • Ricardo--thanks so much for this response. I'll be looking into it this evening! – po.studio Apr 13 '12 at 00:49
  • Ricardo, I edited my original question to incorporate your suggestions. There still seems to be a problem, and I've outlined it in the update. Really appreciate your input! – po.studio Apr 13 '12 at 22:03
  • @PaulOsetinsky inside socket.on 'broadcast', i changed the `record` parameter to `user`, so your code should read `[lat, lng] = record.geometry.coordinates`. And the code for distributing the messages is still missing :) – Ricardo Tomasi Apr 14 '12 at 19:15
  • thanks again Ricardo. Code still not functioning, and I've updated my question with some thoughts. Does the html need to be updated at all? – po.studio Apr 15 '12 at 22:06