れ e Use1 - みる会図書館


検索対象: Building the Realtime User Experience
314件見つかりました。

1. Building the Realtime User Experience

嶬で b Design & Development Building the Realtime User Experience The 嶬で b is increasingly happening in realtime. 嶬宝 h websites such as Facebook and Twitter leading the way' users ℃ coming tO expect that Ⅱ sites should serve content as it occurs¯on smartphones as well as computers. This bOOk shows you h ( ) 从 to build realtime user experiences by adding chat' streaming content' and including at 紅 without making big changes tO the existing infrastructure. You'll alSO learn hOW tO serve realtime content beyond the browser. Throughout the b00k are many practical JavaScript and Python examples that you can use on your site 〃 0 . And in the final chapter, you'll build a location-aware game that combines all of the technologies discussed. Use the latest realtime syndication technologY' including PubSubHubbub BuiId dynamicwidgets on your homepageto show realtime updates from sources ■ Learn h0Wt0 use long polling t0 push" contentfrom your server tO browsers create an application using theTornado web serverthat makes sense Of massive amounts Of streaming content Understand the unique requirements for setting up a basic Chat service Use IM and SMS tO enable usersto interactwith your site outside Ofa web browser lmplementcustom analyticsto measure engagement in realtime ■ ■ 第 ■ Previous experience developing web iS recommended. 。 7 〃な 0 〃召グ〃 川尸阨 / ん〃 0 〃召 〃〃肥わ . 爿叩ド C() 〃 7 わ加 es 4 〃 S 2 / 72 / 〃 鰓〃 / ⅳ〃 . 鹿召リ功 / 〃 g 花ノ es な / 加″ g カ川を昭 / 0 励 0 間″側励 c 砠ツ / 娵ル召 ア / / / ツ翫励 / 加雇 —MarshaIl Kirkpatrick 朝一加ら ReadWriteWeb Ted Roden is a member 0f the Research and Development group at 7 カ e Ne 肥 7 カ〃い , wher ℃ he has extensively 1 ℃ searched topics related tO realtime user experience. 0 REILLY 0 0 「 e Ⅲ y. ( om US $ 34.99 CAN $ 43.99 I S B N : 9 7 8 ー 0 ー 5 9 6 ー 8 0 6 1 5 ー 6 5 3 4 9 9 川ⅧⅢはⅢⅧ馴 II 9 / 8 0 5 9 6 8 0 6 1 5 6 Free online edition fo 「 45 days with purchase of this bOOk. Details on last page. Safarl BooksOnline

2. Building the Realtime User Experience

= data. results[i] ; var tweet / / add the tweet to the UI Home. addLine('trending-on-twitter ・ if(data. results. length) Home. updateTit1e( ・ trending-title' , data. results ・ length); tweet. profile image url profile image ・ ・ html' : tweet. text, , { ・ username' : tweet. from user, The Basic Widgets ー 45 var dOC document; Home. addLine = function(targetDivId, data) { tO the widgets: flicts with existing frameworks. Add the following code for the ability [ 0 add updates widgets can easily be integrated intO existing websites without causing JavaScript con- COde using one Of these libraries, but using the standard methods ensures that these manipulation functions provided by the browser. We could have saved some lines of ternal JavaScript libraries to manipulate the DOM; instead it uses the standard DOM calling Home. addLine t0 display each one in the widget. This method does not use ex- ln the callback function Home. catchTweets, we're looping through all of the tweets and Displaying the updates tO populate Home. twitter since id. makes it easy by providing max id with each result set. We can use that max id variable track of each variable ID that we've seen and calculate the highest number, but Twitter tO limit the tweets in our request tO tweets that we haven't yet seen. We could keep Back in the method Home. getTrendingTweets, we use the variable Home. twitter since id updates. ln calling that method we need to provide only the id of the div and the amount of new widget. That method will update the title pane of the widget to display "x new results. ' ' called Home. updateTit1e that can be used by all of the widgets, not justthe trending the user Of hOW many tweets were just added. TO dO that, we're going tO use a method ln addition [ 0 adding each individualtweet to the widget, it's also a good idea to inform Line, which will add the tweetto the interface. As this method 100PS through each of the tweets, it calls a method called Home. add along with Other information such as the username and even the language Of the tweet. array Of tweets matching the search criteria. Each Object contains the text Of the tweet When this callback methOd is called, its parameter is a data object that contains an data. max id; Home. twitter since id / / cache the max id SO we know which tweets we've seen

3. Building the Realtime User Experience

BuiIding the ReaItime U 史「 Experience by Ted Roden Copyright ◎ 2010 Ted R0den. AII rights reserved. printed in the United States Of America. published by O'Reilly Media, lnc. , 10()5 Gravenstein Highway North, Sebastopol, CA 95472. O'Reilly books may be purchased for educational, business, or sales promotional use. Online editions are alSO available for most titles ( わ p : 〃川 ). sa. / 4 ⅱわ 00 た SO 〃〃〃巳 CO 襯 ). For more information, contact our corporate/institutional sales department: (8()0) 998-9938 or co 挈 ora 化@0 尾卍 ). co 川 . Editor: Simon St. Laurent Production Editor: Kristen Borg Copyeditor: Genevieve d'Entremont Proofreader: Teresa Barensfeld Production Services: Molly Sharp lndexer: Ellen Troutman Cover Designer: Karen Montgomery lnterior Designer: David Futato lllustrator: Robert Romano Printing History: July 2010: First Edition. Nutshell Handbook, the Nutshell Handb00k 10g0 , and the O'Reilly 10g0 are registered trademarks of O'ReiIIy Media, lnc. BuiIding ビ R ビ記ⅲれ e Use1 ・ Ex 〃夜元ら the image of a myna bird, and related trade dress are trademarks 0f O'Reilly Media, lnc. Many Of the designations used by manufacturers and sellers tO distinguish their products are claimed as trademarks. Where those designations appear in this b00k, and O'Reilly Media, lnc. , was aware Of a trademark claim, the designations have been printed in caps or initial caps. WhiIe every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions, or for damages resulting frOI れ the use Of the information con- tained herein. ー This book uses RepKoverTM, a durable and flexible lay_flat binding. ISBN: 978-0-596-80615-6 [M] 1277147714

4. Building the Realtime User Experience

This code operates in a similar fashion t0 the SMSIncomingHandler class. lt simplyfunnels the get and post requests through one method called respond and does all 0f its work ⅲ th method. This method accepts two HTTP parameters per request, the mobile number that will receive this message and the b0dy 0f the message itself. Once we ve collected the HTTP parameters and set up some variables that we'll use when responding tO the request, the next thing tO dO is check tO see whether the user is authenticated. If the user is authenticated, we run the send method for this service and set the response variables accordingly. This is where our standard SMSService in- terface really shines. Although both Zeep M0bile and TextMarks have drastically dif- ferent ways of sending messages, we can simply call this single method and it will get handled, regardless of which service is being used. ln the event that this user iS not authenticated, we refrain from sending the message but still set the response variables. These variables are then logged, encoded t0 JSON, and sent back as the HTTP response. While any response that we provide in the SMSIncomingHand1er sends an SMS message back t0 the user, responding t0 the HTTP request here just sends it back t0 the client making the API request. ln this method, no message iS being sent without calling send. This API method is intentionally simple. ln production use, it should be secured tO ensure that ⅱ can't be used tO send unsolicited SMS mes- sages [ 0 your users. lt wouldn't hurt tO add some error checking as well. Testing the API The idea behind building this API is that other parts ofan application can use it to send messages tO users when needed. SO, tO ensure that these messages can be sent, we need tO test out sending messages from outside this application. TO keep it simple, we'll use the command-line program called curl tO make some requests and test it ou [. FrOl れ the command line, enter the following command: ~ $ curl "http://your-app-id ・ appspot.com/sms/send/via/textmark?mobile number=invalid- number&body=Can + you + hear + me + now?" {"status" "fail" "Not Authenticated: mesg invalid-number"} As expected, calling this method with a totally invalid number ()n this case, invalid- number) fails miserably. But what happens if you use your personal phone number that you've been using tO test? For sake Of this example, let's assume that number is ( 555 ) 555 ー 1212. Try that from the command line: ~ $ curl "http://your-app-id ・ appspot.com/sms/send/via/textmark? mobile numbeて=5555551212&b0dY=Can + you + hear + me + now?" "NOt Authenticated: 5555551212 " } {"status" "fail" ・ mesg While that certainlylooks like it should work, the number provided is not actually the number that we have on file. Each of these SMS services sends us the mobile number in E. 164 ( 厖印 : / ん〃 . ⅵたゆ翻 g / ル測 / E. 7 64 ) , complete with the + prefix. So in this 182 ー朝叩 te 「 8 : 5M5

5. Building the Realtime User Experience

contain the map Object, SO that it can be easily referenced in the different member functlons. The first of those member functions is getLocation, which is a wrapper call for the browsers, own navigator. geolocation. getCurrentPosition meth0d. This method is available on most recent 1 れ Obile browsers and iS even available desktop browsers with increasing frequency. Firefox on the desktop already includes this functionality natively within the browser. Rather than checking tO see whether each browser sup- ports this function every time we want tO call it, we simply call this ipGeo. get Loca tion method, which wraps up that logic and makes the proper success and failure callbacks depending on what happens. Because locating the exact GPS coordinates 0f the browser can take some time, navigator. geolocation. getCurrentPosition runs asynchronously and executes the proper callback when data is available. Aside from the success and fail callback functions, we also pass along a small object with a single key/value pair for maximumAge. Making a getCurrentLocation request is expensive, bOth in terms Of the amount Of time it takes tO return and the drain on batteries it takes tO use a GPS sensor in a mobile device. Setting the maximumAge param- eter tO 3()0 OOO milliseconds allOWS us [ 0 cache the results for five minutes. This amount Of cache time will ensure that any geolocation-based action that takes place in a stand- ard session will require only one actual external request. This alSO stops the result from being cached indefinitely, which is actually the default behavior on some devices. The next method is ipGeo. initialize, which takes in a parameter that is just the ID Of the DIV we're going to use to display the map. This method then checks t0 see whether Google thinks this browser is compatible with their maps API and creates the map object. There are a number of different options ( 印 : / ん 0 . goog . し 0 川ん〃な / a 内 / doc 川 e 〃 0 〃 / 尾を〃記 . 川 / # GMa 〃〇〃行 0 ) that can be used when working with these maps, but we're just going t0 use the default options and tellthe map t0 use the default user interface. Next, we simply call the get Location methOd and, upon success, we center the map on the coordinates it returned and add a marker at the current location. NOW that we've built S01 れ e basic JavaScript functionality intO this application, we need to add it t0 the HTML views. 从々 don't need t0 add this t0 the logged-out page,Just the page where the user has already been authenticated. Open up 川〃 s / 〃ⅲ . 川 / and make the following adjustments: く tit1e>iPandemic く /title> - f0 て jQuery - く script type="text/javascript" src="http://www ・ google ・ com/jsapi"> く /script> - for the maps API - く script src="http://maps ・ google ・ com/maps?file=api&v=2&sensor=true&key= YOUR-GOOGLE-MAPS-API-KEY" type="text/javascript"> く /script> 242 ー ChapterIO: Putting lt 則 Together

6. Building the Realtime User Experience

CHAPTER 7 lnstant Messaging We've already built an example of a fully featured chat application that functions en- tirely in a browser window, but realtime experiences are increasingly happening outside of the browser. Users expect to be able to input data and get it back out not only from an unending array Of mobile devices, but alSO from inside applications that they cur- rently use. This chapter shows an example 0f integrating a web-based application with standard instant messaging protocols and programs. There are many different instant messaging protocols that are in wide use today. Skype, Windows Messenger, AOL lnstant Messenger, and Yahoo! lnstant Messenger all have their own clients and their own protocols. Those are all proprietary protocols that are not technically open to interoperability, but there is a popular open protocol called XMPP ( ん印 : / / 'x 襯 pp. 0 鵬 . Being an open technology, it's supported by many instant messaging clients, including Apple's iChat, Digsby ( 中 : 〃ルルル . 浦 gs エ 0 川 , and Pidgin ( 印 : 〃ルルル . dg ⅲ .i 襯庄 Basically, whatever the platform, there is an application that supports XMPP. The easy availability ofclient applications is a good reason for us to use this technology, but the size of the userbase is another consideration. ThankfuIIy, XMPP has a huge built-in userbase due to Google using it in their GoogIe TaIk service, which is linked to their Gmail service. Google also offers nearly seamless XMPP integration for developers on their cloud computing platform, Google App Engine ( 印 : 〃叩〃 e れ g ⅲ e. goog . co 川 ). 129

7. Building the Realtime User Experience

These additions don't do anything other than configure some variables about how often [ 0 send out SMS alerts, which number to use when sending them, and the API to use in order [ 0 send them. Depending on the traffic you re expecting tO get on your site, you'll probably want [ 0 configure the numbers [ 0 ensure that you re getting enough alert messages, but not tOO many. TO actually send the message, we're going tO have tO monitor the number 0f currently active users on the site. Once that number goes above our newly created Analytics. SMS alert current users, we re going [ 0 send a message. 从々 can easily add that [ 0 the Ana1ytics. update data method. At the bottom of Ana1ytics. update data, after you ve counted the current number Of active users and stored it in the active user count variable, add the following code tO your げ . 〃ツ file: def update data(self) : # did we find a user that isn ・ t looking at anything? delete them! if not len(self. users[x]) : del self. users[x] # if the active user count goes about the 5M5 threshold if active user count 〉 Analytics. SMS alert current use て 5 : # and we haven ・ t recently sent a message 竏 AnaIytics. SMS last send く (time. time() - Ana1ytics.5M5 send interval) : logging ・ inf0("Sending an SMS A1ert ! " ) # note the current time Ana1ytics.5M5 last send = time. time() # build the URL u て 1 = Ana1ytics. SMS_api base url url 十 = ー十 u て 1 escape(Ana1ytics. SMS alert mobile number) url + = '&body= ・ + u て 1 escape("Current1y %d users on the site! " ) % ( len ( 5e1 + ・ users ) ) ) # make the API request f = urllib. urlopen(url) + ・ read() The update data method was already counting the current number of active users, so the only addition we had tO make was tO check whether that number went above our predetermined limit. lfit did, we check tO see whetherwe ve recentlysent out a message, and if not, we simply make the API call to our SMS application. If you set the SMS alert current users low enough, you'll be able to see the SMS message after opening a few tabs on your browser. If you h00k ⅱ up t0 a live site, you should see a message like Figure 屮 8. Customized Analytics ー 215

8. Building the Realtime User Experience

init This JSON object gets sent to the filter class listed in the previous field upon initialization. You can use this space [ 0 pass any variables [ 0 the class that apply tO this specific instance Of the filter. Next, we need tO create the filter class that is called when a publish request is made t0 /river/flow. Open the file 叩 ps / 5 / ma 0 Ⅷな om / te oden 々 1 台 me / F te て p 5 Ⅳ 0 朝 eck. ja Ⅷ and add this: package com.tedroden.realtime; import java. util. Map; import org.com/td.Client; import org.com/td.Channel; import org. cometd. server. filter. JSONDataFilter; public class FilterPasswordCheck extends JSONDataFi1ter String required password; @Override public void init(Object init) super. init(init); required password = (String) ((Map)init) ・ get("required_password"); @Override public Object fi1ter(C1ient from, Channe1 tO, Object data) try { if(((Map)data). get("password"). equals(required password)) return data; else return null; catch (Nu11PointerException e) { return null; The top 0f this file just declares that it's part Of the com.tedroden.realtime package, or whichever namespace you've decided tO use. After that, we import a few Java libraries that this file uses. Then, we just create our filter class, which extends the JSON Data Fi1ter class provided by the cometd distribution. When we set up the lt 5. json file, we specified certain data that got passed to the init function Of the filter. AS you can see, it's the first and only parameter this init function accepts. ・み e pass it along tO the parent class and then grab the required_password, which will be used for the lifetime of this filter. 74 ー Chapter4: River ofContent

9. Building the Realtime User Experience

千て om django ・ utils import simplejson as json This line imports an easy to use JSON-parsing library called simplej son. App Engine offers this module as part of the code to include some compatibility with the Django project ( 印 : 〃ルルル . a 〃 go 〃 ro. は . co 川庄 NormaIIy you'd have to install this module separately, and even compile it tO get the best performance, but including it this way saves several steps. Loading the weather information from YQL is fairly straightforward. Add this function near the top of your 川ⅲ〃 . file: def get_weather for zipcode(zipcode) : # build the YQL statement yql = "select item from weather. forecast where location = %s" % zipcode # encode it for use in a web request yql = yql. replace(" "http://query.yahooapis.com/vl/public/yql?format=json&=%s" % yql url # make the request and parse the json response = urlfetch. fetch(url) response = json. loads(response. content) data try: # return the current weather conditions return data[ ・ query ・ ]['results'][ ・ channel']['item']['condition'] except : return None This method takes a zip code as a parameter and builds a YQL statement with it. That statement gets encoded for use as a URL and is turned intO the actual web request that we'll be using. One Of the limitations Of App Engine is that you re not given direct access tO the net- work. ln order t0 make a web request, you have to use Google's urlfetch module. To make this YQL API request, we can just hand offthe URL to urlfetch. fetch and it will synchronously handle the request and return a response object. The content of that object is the JSON response from the YQL request. This API actually returns a 10t of data about the weather, including the forecast and links tO images that represent the weather, but we're only concerned with the current conditions, SO we parse that part out and return it. TO get the application tO supply the weather information, we need tO add a new com- mand [ 0 the XMPPHandIer class. ln that class, make the following changes: class XMPPHand1er(BaseHandIer) : def post(self) : # add up a11 the numbers elif cmd el 竏 cmd sum weather' Responding lntelligently ー 147

10. Building the Realtime User Experience

That variable is a dictionary ofkey/value pairs that specify the different classes that can be used by this script as an SMS service. This list 0f services will be used to map a plain-text service name tO a class Object that can be instantiated. The next blOCk Of COde does exactly that: it takes the text name Of a service, checks it against the self. supported services list, and instantlates a class if it's a supported servlce. That set_service_type method is called by each controller to inform the SMSBase Hand1er which actual SMS API class we'll be using. For example, using the example self. supported services dictionary defined earlier, the code would call self. set service type(' some service ・ ) tO use the some service Class as the SMS provider. From then on, the controller class, and any COde that it utilizes, does not need tO know which service type is being used. The next method defines the self. service variable and exposes it via the service property. This allows controllers t0 use self. service t0 access any 0f the SMS API functionality. lnstead 0f constantly determining which class is being used with each web request, the controllers can make one call tO self. set service type and then use the interface defined by SMSService. ln practice, it would look very much like this: # NO need tO add this tO your code, it ・ s just an example self. set service_type(' some service ・ ) if not self. service. is authenticated() : "N0t logged in ! " raise Exception, self. service. send(phone number, "Greetings from SMS! " ) Preparing t0 Accept Messages Now that we have defined the basic interface for SMS services as well as a base class to handle the high-level functionality shared by each of the controller classes, let's 100k into responding t0 the SMS requests as they come in. Each 0f these requests will hitthe server as either a POST or GET HTTP request, butthe basic functionality will be the same, regardless of the request method. TO start handling these requests, add the following class to your s 川 s. file: class SMSIncomingHandler(SMSBaseHand1er) : # handle the GET requests def get(self, service_type) : self. respond(service_type) # handle the POST requests def post(self, service_type) : self. respond(service_type) # a11 of the HTTP requests end up handled by this method def respond(self, service_type) : # setup the service type self. set service_type(service type) e1se: Building the Basic Application