I'm using the python version of the newly released Gmail API by Google.
The following call returns just a list of message ids:
service.users().messages().list(userId = 'me').execute()
But then I just have a list of message ids and need to iterate over them and fetch them one-by-one.
Is there a way to get the whole message content for a list of ids, in a single call ?
(Similar to how it's done in the Google Calendar API) ?
And if not supported yet, is this something that Google would like to consider adding in the API ?
Update
Here is the solution that worked for me:
batch = BatchHttpRequest()
for msg_id in message_ids:
batch.add(service.users().messages().get(userId = 'me', id = msg_id['id']), callback = mycallbackfunc)
batch.execute()
Here is an example of batch request in Java where I get all the threads using threads ids. This can be easily adapted for your need.
BatchRequest b = service.batch();
//callback function. (Can also define different callbacks for each request, as required)
JsonBatchCallback<Thread> bc = new JsonBatchCallback<Thread>() {
#Override
public void onSuccess(Thread t, HttpHeaders responseHeaders)
throws IOException {
System.out.println(t.getMessages().get(0).getPayload().getBody().getData());
}
#Override
public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders)
throws IOException {
}
};
// queuing requests on the batch requests
for (Thread thread : threads) {
service.users().threads().get("me", threads.getId()).queue(b, bc);
}
b.execute();
Here is the solution that worked for me:
batch = BatchHttpRequest()
for msg_id in message_ids:
batch.add(service.users().messages().get(userId='me', id=msg_id['id']), callback=mycallbackfunc)
batch.execute()
Related
I'm running RabbitMQ, in a Docker container (rabbitmq:3-management image) as part of a Docker Compose application. The application contains some ASP.NET Core WebApi microservices, which exchange messages via this broker. That works fine and didn't give me any problems so far.
Now I need to publish messages from a Python application to an exchange/queue which was created from one of the ASP.NET Core microservices. The microservice contains a consumer for this queue. For publishing from python, I'm using pika. The problem is, I can't seem to get the publishing right. Whenever I execute my Python script, I can see in the RabbitMQ management UI that a new exchange and queue with the suffix "_skipped" were created. It seems as if my message was sent there instead of the actual queue. Also, when trying to publish directly from the management UI, the message actually makes it to the microservice, but there I'll get an exception, that the message could not be deserialized to a MassTransit envelope object, and also a new exchange and queue with the "_error" suffix.
I have no idea where the problem is. I think the exchange/queue themselves are fine, since other queues/consumers/publishers for microservice to microservice communication in this project work. So then it's probably either how I'm trying to address the exchange/queue from Python, or something with my message body which is not right.
This page gives some info about how messages need to be structured, but not too detailed, and here I got most of the info about how to publish with Python.
Below you see the relevant code regarding the host/queue configuration in the microservice, as well as the Python script. Any help/tips on how I can get this to work would be greatly appreciated.
ASP.NET Core:
// Declaring the host, queue "mappingQueue", consumer in Startup.ConfigureServices of microservice
...
services.AddMassTransit(x =>
{
x.AddConsumer<MappingUpdateConsumer>();
x.AddBus(provider => Bus.Factory.CreateUsingRabbitMq(config =>
{
config.Host(new Uri(RabbitMqConst.RabbitMqRootUri), h =>
{
h.Username(RabbitMqConst.RabbitMqUsername);
h.Password(RabbitMqConst.RabbitMqPassword);
});
config.ReceiveEndpoint("mappingQueue", e =>
{
e.ConfigureConsumer<MappingUpdateConsumer>(provider);
});
}));
});
services.AddMassTransitHostedService();
...
// Consumer
public class MappingUpdateConsumer : IConsumer<MappingUpdateMessage>
{
...
public async Task Consume(ConsumeContext<MappingUpdateMessage> context)
{
await Task.Run(async () =>
{
if (context.Message == null)
{
return;
}
...
});
}
}
// Message class (will have more properties in the future, thus not just using a string consumer)
public class MappingUpdateMessage
{
public string Message { get; set; }
}
Python:
import pika
import json
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='mappingQueue', exchange_type='fanout', durable=True)
message = {
"message" : {
"message": "Hello World"
},
"messageType": [
"urn:message:MassTransit.Tests:ValueMessage"
]
}
channel.basic_publish(exchange='mappingQueue',
routing_key='mappingQueue',
body=json.dumps(message))
connection.close()
print("sent")
For those with the same problem, I figured it out eventually:
..
config.ReceiveEndpoint("mappingQueue", e =>
{
e.ClearMessageDeserializers();
e.UseRawJsonSerializer();
e.ConfigureConsumer<MappingUpdateConsumer>(provider);
});
...
I dumped Python array to a response with json.dumps and now I'm trying to retrieve the data as Javascript list.
#app.route('/get_scales')
#cross_origin()
def get_scales():
classes = inspect.getmembers(sys.modules['mingus.core.scales'], inspect.isclass)
scales = [class_[0] for class_ in classes if ('Error' not in class_[0] and class_[0] != '_Scale')]
return json.dumps(scales)
getScales() {
// create a new XMLHttpRequest
var xhr = new XMLHttpRequest();
// get a callback when the server responds
xhr.addEventListener("load", () => {
// update the state of the component with the result here
console.log(xhr.responseText);
});
// open the request with the verb and the url
xhr.open("GET", "http://127.0.0.1:5000/get_scales");
// send the request
xhr.send();
var formatted_response = JSON.stringify(xhr.responseText);
console.log(JSON.parse(xhr.responseText));
return xhr.responseText;
}
When I made the function in getScales log to console type of xhr.responseText it shows String, but then when trying to parse it with JSON.parse it throws an error. Trying to stringify it first, like above doesn't help either.
I don't know what error it gave, but I think it was actually because xhr.response, wasn't there yet when you tried to use it. This is because XMLrequests function asynchronously, meaning that while the XMLrequest is still waiting for a response, the rest of your code continues executing. Try this instead:
xhr.open('GET', url, false);
the "false" parameter basically says you want your XMLrequest to function synchronously. So the rest of your code will wait for it to finish.
Do keep in mind that your performance may suffer because of this in a lot of situations.
So if you have multiple XMLrequests at a time or Sequentially, you could consider using HTML5 Workers for this.
Or If you don't want your requests to function synchronously (if you can avoid having your XMLrequest function synchronously, you definitely should) you could also try something like this (something like this is defentintely the best option for performance, so if you can use it):
getScales() {
// create a new XMLHttpRequest
var xhr = new XMLHttpRequest();
// get a callback when the server responds
xhr.addEventListener("load", () => {
// update the state of the component with the result here
console.log(xhr.responseText);
var formatted_response = JSON.stringify(xhr.responseText);
console.log(JSON.parse(xhr.responseText));
return xhr.responseText;
});
// open the request with the verb and the url
xhr.open("GET", "http://127.0.0.1:5000/get_scales");
// send the request
xhr.send();
}
I am rather new to flask but what I mean by the title is I want to create a service object which can be used in all controllers or services.
In Java (Spring) I would create a #Bean:
#Configuration
public class WhateverGatewayBeans {
#Value("{whatever.api.key}")
public String apiKey;
#Bean
public WhateverGateway getWhateverGateway() {
return new WhateverGateway(apiKey)
}
}
Which I can now use in all my #Services:
#Service
public class AnyService {
private final WhateverGateway whateverGateway;
#Autowired // Using injection
public AnyService(WhateverGateway whateverGateway) {
this.whateverGateway = whateverGateway;
}
public Something getSomethingFromWhatever(String param) {
return this.whateverGateway.getSomething(param);
}
}
And so on
#Controller
public class AnyController {
private final AnyService anyService;
#Autowired
public AnyController(AnyService anyService) {
this.anyService = anyService;
}
#RequestMapping(name = "/api/whatever")
public Something getSomething(#QueryParam("param") String param) {
return this.anyService.getSomething(param);
}
}
Please note that the above code was written on the fly and likely to be not 100% correct but you get the idea
I am looking for something similar in Flask:
#app.route('/api/something')
def get_something(whatever_gateway):
param = request.args.get('param')
return whatever_gateway.get_something_from_whatever(param)
Here, whatever_gateway should be fully initialized during the server startup. Imagine it has to load for some time, the server should not be up before whatever_gateway is ready.
Typically you instantiate your gateway at module level:
# gateways.py
whatever_gateway = WhateverGateway()
And then just import:
from gateways import whatever_gateway
#app.route('/api/something')
def get_something(whatever_gateway):
param = request.args.get('param')
return whatever_gateway.get_something_from_whatever(param)
There were however other solutions around for dependency injection or you can roll your own. I did it once and it was easy. However later on I realised that most of the time you can get away with just using modules as shown above.
If it takes a while to instantiate the gateway, you can delay that to increase app startup time by wrapping it in some sort of factory:
gateway = None
def get_gateway():
global gateway
if not gateway:
gateway = WhateverGateway()
return gateway
I am trying to get my friend name and ids with Graph API v2.0, but data returns empty:
{
"data": [
]
}
When I was using v1.0, everything was OK with the following request:
FBRequest* friendsRequest = [FBRequest requestForMyFriends];
[friendsRequest startWithCompletionHandler: ^(FBRequestConnection *connection,
NSDictionary* result,
NSError *error) {
NSArray* friends = [result objectForKey:#"data"];
NSLog(#"Found: %i friends", friends.count);
for (NSDictionary<FBGraphUser>* friend in friends) {
NSLog(#"I have a friend named %# with id %#", friend.name, friend.id);
}
}];
But now I cannot get friends!
In v2.0 of the Graph API, calling /me/friends returns the person's friends who also use the app.
In addition, in v2.0, you must request the user_friends permission from each user. user_friends is no longer included by default in every login. Each user must grant the user_friends permission in order to appear in the response to /me/friends. See the Facebook upgrade guide for more detailed information, or review the summary below.
If you want to access a list of non-app-using friends, there are two options:
If you want to let your people tag their friends in stories that they publish to Facebook using your App, you can use the /me/taggable_friends API. Use of this endpoint requires review by Facebook and should only be used for the case where you're rendering a list of friends in order to let the user tag them in a post.
If your App is a Game AND your Game supports Facebook Canvas, you can use the /me/invitable_friends endpoint in order to render a custom invite dialog, then pass the tokens returned by this API to the standard Requests Dialog.
In other cases, apps are no longer able to retrieve the full list of a user's friends (only those friends who have specifically authorized your app using the user_friends permission). This has been confirmed by Facebook as 'by design'.
For apps wanting allow people to invite friends to use an app, you can still use the Send Dialog on Web or the new Message Dialog on iOS and Android.
UPDATE: Facebook have published an FAQ on these changes here: https://developers.facebook.com/docs/apps/faq which explain all the options available to developers in order to invite friends etc.
Although Simon Cross's answer is accepted and correct, I thought I would beef it up a bit with an example (Android) of what needs to be done. I'll keep it as general as I can and focus on just the question. Personally I wound up storing things in a database so the loading was smooth, but that requires a CursorAdapter and ContentProvider which is a bit out of scope here.
I came here myself and then thought, now what?!
The Issue
Just like user3594351, I was noticing the friend data was blank. I found this out by using the FriendPickerFragment. What worked three months ago, no longer works. Even Facebook's examples broke. So my issue was 'How Do I create FriendPickerFragment by hand?
What Did Not Work
Option #1 from Simon Cross was not strong enough to invite friends to the app. Simon Cross also recommended the Requests Dialog, but that would only allow five requests at a time. The requests dialog also showed the same friends during any given Facebook logged in session. Not useful.
What Worked (Summary)
Option #2 with some hard work. You must make sure you fulfill Facebook's new rules: 1.) You're a game 2.) You have a Canvas app (Web Presence) 3.) Your app is registered with Facebook. It is all done on the Facebook developer website under Settings.
To emulate the friend picker by hand inside my app I did the following:
Create a tab activity that shows two fragments. Each fragment shows a list. One fragment for available friend (/me/friends) and another for invitable friends (/me/invitable_friends). Use the same fragment code to render both tabs.
Create an AsyncTask that will get the friend data from Facebook. Once that data is loaded, toss it to the adapter which will render the values to the screen.
Details
The AsynchTask
private class DownloadFacebookFriendsTask extends AsyncTask<FacebookFriend.Type, Boolean, Boolean> {
private final String TAG = DownloadFacebookFriendsTask.class.getSimpleName();
GraphObject graphObject;
ArrayList<FacebookFriend> myList = new ArrayList<FacebookFriend>();
#Override
protected Boolean doInBackground(FacebookFriend.Type... pickType) {
//
// Determine Type
//
String facebookRequest;
if (pickType[0] == FacebookFriend.Type.AVAILABLE) {
facebookRequest = "/me/friends";
} else {
facebookRequest = "/me/invitable_friends";
}
//
// Launch Facebook request and WAIT.
//
new Request(
Session.getActiveSession(),
facebookRequest,
null,
HttpMethod.GET,
new Request.Callback() {
public void onCompleted(Response response) {
FacebookRequestError error = response.getError();
if (error != null && response != null) {
Log.e(TAG, error.toString());
} else {
graphObject = response.getGraphObject();
}
}
}
).executeAndWait();
//
// Process Facebook response
//
//
if (graphObject == null) {
return false;
}
int numberOfRecords = 0;
JSONArray dataArray = (JSONArray) graphObject.getProperty("data");
if (dataArray.length() > 0) {
// Ensure the user has at least one friend ...
for (int i = 0; i < dataArray.length(); i++) {
JSONObject jsonObject = dataArray.optJSONObject(i);
FacebookFriend facebookFriend = new FacebookFriend(jsonObject, pickType[0]);
if (facebookFriend.isValid()) {
numberOfRecords++;
myList.add(facebookFriend);
}
}
}
// Make sure there are records to process
if (numberOfRecords > 0){
return true;
} else {
return false;
}
}
#Override
protected void onProgressUpdate(Boolean... booleans) {
// No need to update this, wait until the whole thread finishes.
}
#Override
protected void onPostExecute(Boolean result) {
if (result) {
/*
User the array "myList" to create the adapter which will control showing items in the list.
*/
} else {
Log.i(TAG, "Facebook Thread unable to Get/Parse friend data. Type = " + pickType);
}
}
}
The FacebookFriend class I created
public class FacebookFriend {
String facebookId;
String name;
String pictureUrl;
boolean invitable;
boolean available;
boolean isValid;
public enum Type {AVAILABLE, INVITABLE};
public FacebookFriend(JSONObject jsonObject, Type type) {
//
//Parse the Facebook Data from the JSON object.
//
try {
if (type == Type.INVITABLE) {
//parse /me/invitable_friend
this.facebookId = jsonObject.getString("id");
this.name = jsonObject.getString("name");
// Handle the picture data.
JSONObject pictureJsonObject = jsonObject.getJSONObject("picture").getJSONObject("data");
boolean isSilhouette = pictureJsonObject.getBoolean("is_silhouette");
if (!isSilhouette) {
this.pictureUrl = pictureJsonObject.getString("url");
} else {
this.pictureUrl = "";
}
this.invitable = true;
} else {
// Parse /me/friends
this.facebookId = jsonObject.getString("id");
this.name = jsonObject.getString("name");
this.available = true;
this.pictureUrl = "";
}
isValid = true;
} catch (JSONException e) {
Log.w("#", "Warnings - unable to process Facebook JSON: " + e.getLocalizedMessage());
}
}
}
Facebook has revised their policies now. You can’t get the whole friendlist anyway if your app does not have a Canvas implementation and if your app is not a game. Of course there’s also taggable_friends, but that one is for tagging only.
You will be able to pull the list of friends who have authorised the app only.
The apps that are using Graph API 1.0 will be working till April 30th, 2015 and after that it will be deprecated.
See the following to get more details on this:
User Friends
Facebook Application Development FAQ
In Swift 4.2 and Xcode 10.1:
If you want to get the friends list from Facebook, you need to submit your app for review in Facebook. See some of the Login Permissions:
Login Permissions
Here are the two steps:
1) First your app status is must be in Live
2) Get required permissions form Facebook.
1) Enable our app status live:
Go to the apps page and select your app
https://developers.facebook.com/apps/
Select status in the top right in Dashboard.
Submit privacy policy URL
Select category
Now our app is in Live status.
One step is completed.
2) Submit our app for review:
First send required requests.
Example: user_friends, user_videos, user_posts, etc.
Second, go to the Current Request page
Example: user_events
Submit all details
Like this submit for all requests (user_friends , user_events, user_videos, user_posts, etc.).
Finally submit your app for review.
If your review is accepted from Facebook's side, you are now eligible to read contacts, etc.
As Simon mentioned, this is not possible in the new Facebook API. Pure technically speaking you can do it via browser automation.
this is against Facebook policy, so depending on the country where you live, this may not be legal
you'll have to use your credentials / ask user for credentials and possibly store them (storing passwords even symmetrically encrypted is not a good idea)
when Facebook changes their API, you'll have to update the browser automation code as well (if you can't force updates of your application, you should put browser automation piece out as a webservice)
this is bypassing the OAuth concept
on the other hand, my feeling is that I'm owning my data including the list of my friends and Facebook shouldn't restrict me from accessing those via the API
Sample implementation using WatiN:
class FacebookUser
{
public string Name { get; set; }
public long Id { get; set; }
}
public IList<FacebookUser> GetFacebookFriends(string email, string password, int? maxTimeoutInMilliseconds)
{
var users = new List<FacebookUser>();
Settings.Instance.MakeNewIeInstanceVisible = false;
using (var browser = new IE("https://www.facebook.com"))
{
try
{
browser.TextField(Find.ByName("email")).Value = email;
browser.TextField(Find.ByName("pass")).Value = password;
browser.Form(Find.ById("login_form")).Submit();
browser.WaitForComplete();
}
catch (ElementNotFoundException)
{
// We're already logged in
}
browser.GoTo("https://www.facebook.com/friends");
var watch = new Stopwatch();
watch.Start();
Link previousLastLink = null;
while (maxTimeoutInMilliseconds.HasValue && watch.Elapsed.TotalMilliseconds < maxTimeoutInMilliseconds.Value)
{
var lastLink = browser.Links.Where(l => l.GetAttributeValue("data-hovercard") != null
&& l.GetAttributeValue("data-hovercard").Contains("user.php")
&& l.Text != null
).LastOrDefault();
if (lastLink == null || previousLastLink == lastLink)
{
break;
}
var ieElement = lastLink.NativeElement as IEElement;
if (ieElement != null)
{
var htmlElement = ieElement.AsHtmlElement;
htmlElement.scrollIntoView();
browser.WaitForComplete();
}
previousLastLink = lastLink;
}
var links = browser.Links.Where(l => l.GetAttributeValue("data-hovercard") != null
&& l.GetAttributeValue("data-hovercard").Contains("user.php")
&& l.Text != null
).ToList();
var idRegex = new Regex("id=(?<id>([0-9]+))");
foreach (var link in links)
{
string hovercard = link.GetAttributeValue("data-hovercard");
var match = idRegex.Match(hovercard);
long id = 0;
if (match.Success)
{
id = long.Parse(match.Groups["id"].Value);
}
users.Add(new FacebookUser
{
Name = link.Text,
Id = id
});
}
}
return users;
}
Prototype with implementation of this approach (using C#/WatiN) see https://github.com/svejdo1/ShadowApi. It is also allowing dynamic update of Facebook connector that is retrieving a list of your contacts.
Try /me/taggable_friends?limit=5000 using your JavaScript code
Or
try the Graph API:
https://graph.facebook.com/v2.3/user_id_here/taggable_friends?access_token=
If you are still struggling with this issue on a development mode.
Follow the same process as mentioned below:
create a test app of your main app,
create test users, automatically install app for test users and assign them 'user_friend' permission.
Add your test users as a friend with each other.
I followed the same process after going through alot of research and finally it worked.
In the Facebook SDK Graph API v2.0 or above, you must request the user_friends permission from each user in the time of Facebook login since user_friends is no longer included by default in every login; we have to add that.
Each user must grant the user_friends permission in order to appear in the response to /me/friends.
let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()
fbLoginManager.loginBehavior = FBSDKLoginBehavior.web
fbLoginManager.logIn(withReadPermissions: ["email","user_friends","public_profile"], from: self) { (result, error) in
if (error == nil) {
let fbloginresult : FBSDKLoginManagerLoginResult = result!
if fbloginresult.grantedPermissions != nil {
if (fbloginresult.grantedPermissions.contains("email")) {
// Do the stuff
}
else {
}
}
else {
}
}
}
So at the time of Facebook login, it prompts with a screen which contain all the permissions:
If the user presses the Continue button, the permissions will be set. When you access the friends list using Graph API, your friends who logged into the application as above will be listed
if ((FBSDKAccessToken.current()) != nil) {
FBSDKGraphRequest(graphPath: "/me/friends", parameters: ["fields" : "id,name"]).start(completionHandler: { (connection, result, error) -> Void in
if (error == nil) {
print(result!)
}
})
}
The output will contain the users who granted the user_friends permission at the time of login to your application through Facebook.
{
data = (
{
id = xxxxxxxxxx;
name = "xxxxxxxx";
}
);
paging = {
cursors = {
after = xxxxxx;
before = xxxxxxx;
};
};
summary = {
"total_count" = 8;
};
}
You have a python script diagnosis.py that generates realtime event-based data. Using Node.js, you can launch it as a child process and capture its output and then using Socket.IO emit that to the client and present it using HTML.
Server
var util = require('util'),
spawn = require('child_process').spawn,
ls = spawn('python', ['diagnosis.py']);
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, fs = require('fs')
app.listen(80);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.sockets.on('connection', function (socket) {
ls.stdout.on('data', function (gdata) {
socket.emit('news', gdata.toString());
});
});
Client
<html>
<head>
<script src="/socket.io/socket.io.js"></script>
<script>
var d = "";
var socket = io.connect('http://localhost');
socket.on('news', function (data) {
d += data;
document.getElementById('data').innerHTML = d;
console.log(data);
});
</script>
</head>
<body>
<div id="data"></div>
</body>
</html>
Question
This is great and all, but what if you're looking for the same HTML-Node.js communicative power that Socket.IO provides but instead between Node.js and Python? How would you do that? There's no web server there, so Socket.IO does not make a lot of sense and communicating over bare TCP does not provide the same power/elegance. How do I achieve full duplex communication between Node.js and Python?
Update I answered my own question, but I'm open to an alternative approach. RPC doesn't quite do what I want though.
Apache Thrift is a pretty awesome way to write RPC code between all of the major languages. You write a generic Thrift spec declaring the types and services, and then the code generator creates bindings for your desired languages. You can have apis for calling methods between your node and python code bases.
On a more generic low level approach, ZeroMQ is a message queue library that also has support for all of the major languages. With this, you can design your own solution for how you want to communicate (not just purely RPC). It has patterns for request/reply, push/pull, pub/sub, and pair. It gives you enough tools to put together a scalable system of any type.
I have used both and they are great solutions.
Just as a very rough example, the Thrift spec may be something like this. Lets say you want to communicate events from python to node.js, have it processed and get back some response:
myspec.thrift
struct Event {
1: string message;
}
service RpcService {
string eventOccurred(1:Event e)
}
This defines a data structure called Event with a single string member to hold the message. Then a service called RpcService define one function called eventOccured which expects an Event as an argument, and will return a string.
When you generate this code for python and node.js, you can then use the client side code for python and the server side code for node.js
python
from myrpc import RpcService, ttypes
# create a connection somewhere in your code
CONN = connect_to_node(port=9000)
def someoneClickedSomething():
event = ttypes.Event("Someone Clicked!")
resp = CONN.eventOccurred(event)
print "Got reply:", resp
node.js
// I don't know node.js, so this is just pseudo-code
var thrift = require('thrift');
var myrpc = require('myrpc.js');
var server = thrift.createServer(myrpc.RpcService, {
eventOccurred: function(event) {
console.log("event occured:", event.message);
success("Event Processed.");
},
});
server.listen(9000);
You can look at some messaging systems like 0mq http://www.zeromq.org/
I used the library inspired by this question to turn diagnosis.py into a Socket.IO client. This way I can emit the realtime data to the Node.js Socket.IO server:
socketIO.emit('gaze', ...)
And then have it do a socket.broadcast.emit to emit the data to all the Socket.IO clients (browser and diagnosis.py).
RPC is probably the more standard approach for cross-language development but I find it's a bit of an overkill to do that when the goal is to exchange data. It also does not support evented IO out of the box.
Update on Jan 2013 Since socket.broadcast.emit generates a lot of unnecessary traffic, I tried to find a better way of doing this. The solution I came up with is to use namespaces which is supported by the basic python Socket.IO client library I mentioned.
Python
self.mainSocket = SocketIO('localhost', 80)
self.gazeSocket = self.mainSocket.connect('/gaze')
self.gazeSocket.emit('gaze', ...)
To connect to the gaze namespace.
Node.js
var gaze = io.of('/gaze').on('connection', function (socket) {
socket.on('gaze', function (gdata) {
gaze.emit('gaze', gdata.toString());
});
});
This emits the data received only to clients connected to the gaze namespace.
Browser
var socket = io.connect('http://localhost/gaze');
socket.on('gaze', function (data) {
console.log(data);
});
If you're just looking for something that gives you a simple protocol on top of sockets, so you don't have to deal with buffering and delimiting messages and all that stuff, the two obvious choices (depending on what kind of data you're trying to send) are netstrings and JSON-RPC. There are multiple choices of libraries for both, in both languages, but you can end up with code as simple as this:
class MyService(Service):
# … code to set up the newsdb
def getnews(self, category, item):
return self.newsdb.get(category, item)
myService = MyService(6000)
myService = Service(6000)
// … code to set up the newsdb
myService.getnews = function(category, item, callback) {
callback(this.newsdb.get(category, item);
}