Google App Engine,按钮点击后连续启动/停止脚本

时间:2016-08-31 08:10:13

标签: python google-app-engine

我正在寻找有关如何实现函数启动/停止功能的指导,这使得restAPI能够通过{{1}点击呈现的html页面上的按钮,连续地检索JSON格式的数据并托管在GAE上?

当前行为是一旦http请求完成,被调用的函数当然会停止(webapp2)(根据GAE文档的正常行为)。

main.py:

while self._running == True

page.html:

#!/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)

1 个答案:

答案 0 :(得分: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(...)