2016-08-31 9 views
1

restAPIのデータをJSON形式で連続的に取得する機能の開始/停止機能を達成する方法のガイダンスを探しています。レンダリングされたHTMLページはwebapp2まであり、GAEでホストされていますか?Google App Engine、ボタンをクリックして継続的にスクリプトを開始/停止する

現在の動作は、http要求が完了すると、もちろん呼び出された機能は停止します(while self._running == True)(GAEのドキュメントに従って正常な動作)。

main.py:

#!/usr/bin/env python 
# 
import webapp2 
from google.appengine.api import urlfetch 
from matplotlib.path import Path as mpPath 
import json 
import base64 
import socket 
import logging 
from threading import Thread 
import jinja2 

template_dir = os.path.join(os.path.dirname(__file__)) 
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), 
      extensions=['jinja2.ext.autoescape'], autoescape=True) 

# create a UDP socket for sending the commands 
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) 

# create the stop/start functionality of a thread that runs infinite until 
# thread is terminated 

class CMX: 
    def __init__(self): 
     self._running = True 

    def terminate(self): 
     self._running = False 

    def run(self): 
     storedCredentials = False 
     username = None 
     password = None 

     ip_address = 'someip'     # commands are send to the broadcast address for addressing the zones(bays) 
     port = someport      # use of port 50011 because no return packet is send back, could cause the 
               # lights not to execute the command when using broadcast. 

     # define the boundaries of the different zones 
     zone = [[(106.03,141.19),(158.94,141.19),(158.94,194.50),(106.03,194.50)], 
       [(103.76,168),(62.26,168),(62.26,77.86),(103.67,77.86)], 
       [(106.38,77.86),(191.95,77.86),(191.95,106.52),(106.38,106.52)]] 

     flag_zone_1 = False 
     flag_zone_2 = False 
     flag_zone_3 = False 

     while self._running == True: 

      restURL = 'http://someurl' 
      print restURL 

      if not storedCredentials: 
       username = 'username' 
       password = 'password' 
       storedCredentials = True 
      try: 
       request = urlfetch.fetch(url = restURL, headers={"Authorization": "Basic %s" % base64.b64encode(username +':'+ password)}) 

       <perform actions and other function calls> 
       . 
       . 

      except urlfetch.Error: 
       logging.exception('Caught exception fetching url') 


class Handler(webapp2.RequestHandler): 
    def write(self, *a, **kw): 
     self.response.out.write(*a, **kw) 

    def render_str(self, template, **params): 
     t = jinja_env.get_template(template) 
     return t.render(params) 

    def render(self, template, **kw): 
     self.write(self.render_str(template, **kw))   

class MainPage(Handler): 
    def get(self): 
     button = "Start Demo" 
     running = False 
     self.render('page.html', button = button, run = running) 

    def post(self): 
     startDemo = CMX() 
     t = Thread(target=startDemo.run, args=()) 
     t.daemon = True 

     if self.request.get('button') == "Start Demo": 
      button = "Stop Demo" 
      running = True 
      self.render('page.html', button = button, run = running) 
      t.start() 

     else: 
      button = "Start Demo" 
      running = False 
      self.render('page.html', button = button, run = running) 
      startDemo.terminate() 


def which_zone(xcoord, ycoord, zone): 
    point = (xcoord, ycoord) 
    in_zone_1 = mpPath(zone[0]).contains_point(point) 
    in_zone_2 = mpPath(zone[1]).contains_point(point) 
    in_zone_3 = mpPath(zone[2]).contains_point(point) 

    if in_zone_1 == True: 
    return "Zone 1" 
    elif in_zone_2 == True: 
    return "Zone 2" 
    elif in_zone_3 == True: 
    return "Zone 3" 

def dim_lights(ip_address, port, control_string, sock): 
    control_string = control_string + 'S0F10' +'\r' 
    #sock.sendto(control_string, (ip_address, port)) 
    return control_string 

def norm_lights(ip_address, port, control_string, sock): 
    control_string = control_string + 'S255F10' +'\r' 
    #sock.sendto(control_string, (ip_address, port)) 
    return control_string 

app = webapp2.WSGIApplication([('/', MainPage)], debug=True) 

page.html:

{% extends "base.html" %} 

{% block comment %} 
{% autoescape true %} 
    <form method="post"> 
      <div> 
       <input type="submit" name="button" value="{{button}}"> 
       <input type="hidden" name="run" value="{{run}}"> 
      </div> 
      <!-- <div>macAddress: <input type="text" name="macAddress"><br> 
       <input type="submit" value="Submit"> 
      </div> --> 

    </form> 
{% endautoescape %} 
{% endblock %} 

答えて

0

スタート/ストップ機能は簡単です - ちょうどボタンコントロールを作るoperation_is_stoppedフラグのようなものがで(リクエスト間持続たとえば、データストア)。

まだ理解していない場合は、そのボタンで制御したいと思っているの操作を連続で達成することが本当に困難です。これはGAEと実際には互換性がありません - GAEのすべてがリクエストに応答することを中心に、は限られた時間でです。あなたは実際にGAEで無期限に実行するプロセス/スレッドを持つことはできません。

しかし、多くの場合、短命の操作の流れとして(あなたと同じように)長時間実行される反復的な連続操作を実装することは可能です。 task queuesを使用して簡単に達成できるGAEでは、各繰り返し(ケースではwhile self._running == Trueループの本体)がタスクキュー要求への応答として実装されます。

フローは、「開始」アクションがトリガーされたときにそれぞれのタスクをエンキューすることによって開始されます。前のタスク要求の処理後にそれぞれのタスクをエンキューすることによって、フローが維持されます。

def post(self): # handler for the "long running" task requests 

    # need to rebuild/restore your request context every time 
    ... 

    try: 
     request = urlfetch.fetch(...) 
     <perform actions and other function calls> 
    except: 
     ... 

    finally: 
     if not operation_is_stopped: 
      # enqueue another "long running" task 
      task = taskqueue.add(...) 
+0

おかげでダン、あなたの答えは良い洞察力で私を提供し、そう難しいがのため、GAEタイミングから出て来ていた。そしてそれは、新しいタスク:)これらの線に沿って

何かをエンキューないによって停止しています長い実行要求と応答が30秒以内にクライアントによって受信される必要があります。私は、GAEが実際にsock.sendto()コマンドに必要なプライベートIPアドレスに接続できないことに気付きました。しかし、私は今実行しているフラスコで私の問題を解決しようとし、私は残りのAPIの連続ループを実行するためにsubprocess.Popen()を使用しています。 –

関連する問題