Building Python web app on GAE tw3gsucks, a 3G network speed test web app. PyHUG Tsai, Shih-Chang 2011/12/21
It all starts with... 3G network is really SUCKS!!! I'm used to live in a connected world! Bad network quality/bandwidth makes me crazy!!!
Is there anything I can do? Yes! But maybe we can do it more interestingly!
Google Map! Bandwidth data alone is really boring. What if we put these data on maps?
tw3gsucks project profile Open source project Url: http://tw3gsucks.appspot.com Github - https://github.com/jacksctsai/tw3gsucks
How tw3gsucks works
GAE is good place to start! Google Application Engine https://appengine.google.com/ Python natively supported - Good! Database support - Good! Given a domain name like yourapp.appspot.com - Even better! Tutorials, many documents & sample code It's all FREE & Ready to go! - Huge Win!!!
Techniques involved HTML5 - GPS support jquery - Controlling UI & download sample data Python + Django - Service side programming GAE - App hosting & Database support Google Map - Showing map Github - Version control these are all new to me... :P
GAE - Get Started A google ID (of course.) GAE SDK is a beginner's good friend! Download GAE SDK at http://code.google.com/intl/zh-tw/appengine/downloads.html
A Sample Application More info on app.yaml goto: http://code.google.com/intl/zh-tw/appengine/docs/python/config/appconfig.html
A basic GAE python program import os from google.appengine.ext.webapp import template from google.appengine.ext import webapp from google.appengine.ext.webapp.util import run_wsgi_app class MainPage(webapp.RequestHandler): def get(self): template_values = { 'key': value } path = os.path.join(os.path.dirname( file ), 'index.html') self.response.out.write(template.render(path, template_values)) application = webapp.wsgiapplication([ ('/', MainPage) ], debug=true) def main(): run_wsgi_app(application) if name == ' main ': main()
app.yaml for tw3gsucks application: tw3gsucks version: 1 runtime: python api_version: 1 inbound_services: - warmup handlers: - url: /css static_dir: css - url: /payload static_dir: payload - url: /showmap script: signalreportgen.py - url: /favicon.ico static_files: static/images/favicon.ico upload: static/images/favicon.ico - url: /.* script: reportsignal.py
Location - enabling GPS <html> <script> function locationgot(position) { $("#require_gps").hide(); $("input[name='location']").val(position.coords.latitude+', ' + position.coords.longitude); $("#reportpanel").fadein(); test(); } $(".msg").hide(); $(".result").hide(); if (navigator.geolocation) { $("#require_gps").fadein(); navigator.geolocation.getcurrentposition(locationgot); } else { } </script> </html>
Bandwidth detection This is a little bit tricky. <html> <script> var time1; var bytesloaded = 499717; function test() { $(":submit").attr("disabled", true); var d = new Date; time1 = d.gettime(); $.get( 'payload/speedtestpayload.html', function(obj) { var d = new Date; var time = Math.round((d.getTime()-time1)/10)/100; // 取秒以下兩位小數 var connspeed = Math.round (bytesloaded/time/1000); // 單位 :Kbytes per second $("input[name='speed']").val(connspeed); $(":submit"). attr("disabled", false); } ); } </script> </html>
Storing data on GAE database Create Data Model: from google.appengine.ext import db class SignalReport(db.Model): """Models an individual signal report entry, geolocation, connection info, ip address, and date.""" location = db.geoptproperty() speed = db.integerproperty() tech = db.stringproperty() provider = db.stringproperty() ip = db.stringproperty() date = db.datetimeproperty(auto_now_add=true)
Storing data on GAE database Save data: import os from google.appengine.ext import webapp from google.appengine.ext import db class MainPage(webapp.RequestHandler): def get(self): path = os.path.join(os.path.dirname( file ), 'index.html') self.response.out.write(template.render(path, [])) def post(self): location = self.request.get('location').split(', ') provider_tech = self.request.get('provider_tech').split(' ') // provider_tech is like 中華電信 3G speed = self.request.get('speed') signalreport = SignalReport() if speed.isdigit(): signalreport.speed = int(speed) signalreport.location = db.geopt(lat = location[0], lon=location[1]) signalreport.tech = provider_tech[1] signalreport.provider = provider_tech[0] signalreport.ip = self.request.remote_addr signalreport.put()
Retrieving data and applying template class ShowMap2Page(webapp.RequestHandler): def get(self): signal_query = SignalReport.all() signals = signal_query.fetch(signal_query.count()) template_values = { 'signals': signals } path = os.path.join(os.path.dirname( file ), 'showmaptest.html') self.response.out.write(template.render(path, template_values))
Integrating Google Map <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> <script type="text/javascript"> var map = new google.maps.map(document.getelementbyid("map_canvas"), myoptions); var mylatlng = new google.maps.latlng({{ signal.location.lat }}, {{ signal.location.lon }}); var contentstring = '<div id="content">'+ '<div id="landmarknotice">'+ '<img src=badimage />'+ ' 實測每秒 {{ signal.speed }} KB ({{ signal.provider }} {{ signal.tech }})'+ '</div>'+ '<p> {{ signal.datestr }}</p>'+ '<p><font size="-1"> 經緯度 :{{ signal.location.lon }},{{ signal.location.lat }}</font></p>'+ '</div>'; var infowindow = new google.maps.infowindow({ content: contentstring }); var marker = new google.maps.marker({ position: mylatlng, map: map, icon: BadImage, title: " 測速 {{ signal.speed }} kbps" }); google.maps.event.addlistener(marker, 'click', createenclosur(map,marker, infowindow)); </script>
Something missing Carrier identification (using IP addr, perhaps) Better map presentation
Show Time