apprtc demo的apprtc.py分析

概述

apprtc比較重要的一個文件是apprtc.py文件。
在客戶端連接房間服務器時,我們可以看到除了GAE的modules.py打印信息外,apprtc.py也打印出信息。
今天我們就來搞清楚apprtc.py到底在做什麼。

抓主幹

在apprtc.py的最後,我們看到了這樣的代碼

app = webapp2.WSGIApplication([
    ('/', MainPage), 
    ('/a/', analytics_page.AnalyticsPage),
    ('/compute/(\w+)/(\S+)/(\S+)',     compute_page.ComputePage),
    ('/join/([a-zA-Z0-9-_]+)', JoinPage),
    ('/leave/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)', LeavePage),
    ('/bye/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)', LeavePage),
    ('/message/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)', MessagePage),
    ('/params', ParamsPage),
    ('/r/([a-zA-Z0-9-_]+)', RoomPage),
], debug=True)

webapp2.WSGIApplication表明使用webapp2框架進行webapp的開發。
在網上找到GAE的webapp框架的介紹http://lampeter123.iteye.com/blog/390536
根據其中的介紹,我們可以梳理出apprtc.py的主幹或者說apprtc房間服務器的主幹。
一個 webapp 程序包含三個部分:
一個或多個 RequestHandler類用來處理請求和產生響應。
一個 WSGIApplication 實例用來根據發送請求的URL對應到相應的類
一個主程序用來運行 WSGIApplication(使用CGI adaptor)

app的debug=True會 打印調試信息,如果做成產品後,則可以不打印。
apprtc.py中app就是一個WSGIApplication的實例,用將請求的URL對應到對應的類。
app的對應關係爲
('/', MainPage),
('/a/', analytics_page.AnalyticsPage),
('/compute/(\w+)/(\S+)/(\S+)', compute_page.ComputePage),
('/join/([a-zA-Z0-9-_]+)', JoinPage),
('/leave/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)', LeavePage),
('/bye/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)', LeavePage),
('/message/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)', MessagePage),
('/params', ParamsPage),
('/r/([a-zA-Z0-9-_]+)', RoomPage),

具體分析

上面的代碼定義了一個request handler MainPage,映射到根目錄URL(/)。當房間服務器接收到客戶端的一個http GET URL/的請求後,他會初始化MainPage類,然後調用這個實力的get方法。

class MainPage內容

class MainPage(webapp2.RequestHandler):
  def write_response(self, target_page, params={}):
    template = jinja_environment.get_template(target_page)
    content = template.render(params)
    self.response.out.write(content)

  def get(self):                                                     //
    """Renders index.html."""
    if self.request.headers['Host'] == 'apprtc.net':
      webapp2.redirect('https://www.apprtc.net', permanent=True)
    # Parse out parameters from request.
    params = get_room_parameters(self.request, None, None, None)
    # room_id/room_link will not be included in the returned parameters
    # so the client will show the landing page for room selection.
    self.write_response('index_template.html', params)

在GET方法中,請求信息通過self.request獲得,可以看到房間服務器獲得GET請求根目錄的請求後,所做的是判斷頭中Host內容並重定向到一個域名並獲取房間參數,並將index_template.html模板對應部分填充客戶端輸入的房間信息,然後返回給客戶端。

加入房間時,提交的應該是join,其對應的處理類爲JoinPage,其內容如下:

class JoinPage(webapp2.RequestHandler):
  def write_response(self, result, params, messages):
    # TODO(tkchin): Clean up response format. For simplicity put everything in
    # params for now.
    params['messages'] = messages
    self.response.write(json.dumps({
      'result': result,
      'params': params
    }))

  def write_room_parameters(self, room_id, client_id, messages, is_initiator):
    params = get_room_parameters(self.request, room_id, client_id, is_initiator)
    self.write_response('SUCCESS', params, messages)

  def post(self, room_id):
    client_id = generate_random(8)
    is_loopback = self.request.get('debug') == 'loopback'
    result = add_client_to_room(self.request, room_id, client_id, is_loopback)
    if result['error'] is not None:
      logging.info('Error adding client to room: ' + result['error'] + \
          ', room_state=' + result['room_state'])
      self.write_response(result['error'], {}, [])
      return

    self.write_room_parameters(
        room_id, client_id, result['messages'], result['is_initiator'])
    logging.info('User ' + client_id + ' joined room ' + room_id)
    logging.info('Room ' + room_id + ' has state ' + result['room_state'])

提交Http 的Post請求到join/roomID時,初始化JoinPage類並且用post函數來處理。

//計算一個clietn_id值
client_id = generate_random(8)
//判斷是否是本地測試;
is_loopback = self.request.get('debug') == 'loopback'
//添加客戶端到房間的結果
result = add_client_to_room(self.request, room_id, client_id, is_loopback)
if result['error'] is not None:
//錯誤信息輸出並退出
      logging.info('Error adding client to room: ' + result['error'] + \
          ', room_state=' + result['room_state'])
      self.write_response(result['error'], {}, [])
      return
//獲取房間參數並返回房間參數信息給客戶端,包括client_ID
    self.write_room_parameters(
        room_id, client_id, result['messages'], result['is_initiator'])
//打印日誌信息
    logging.info('User ' + client_id + ' joined room ' + room_id)
    logging.info('Room ' + room_id + ' has state ' + result['room_state'])
  def write_room_parameters(self, room_id, client_id, messages, is_initiator):
    params = get_room_parameters(self.request, room_id, client_id, is_initiator)
    self.write_response('SUCCESS', params, messages)
 def write_response(self, result, params, messages):
    # TODO(tkchin): Clean up response format. For simplicity put everything in
    # params for now.
    params['messages'] = messages
    self.response.write(json.dumps({
      'result': result,
      'params': params
    }))

進入房間後,應該提交http Get 到/r/roomId信息到房間服務器,此時初始化class roompage。其內容爲

class RoomPage(webapp2.RequestHandler):                           //回調函數
  def write_response(self, target_page, params={}):
    template = jinja_environment.get_template(target_page)
    content = template.render(params)
    self.response.out.write(content)

  def get(self, room_id):
    """Renders index.html or full.html."""
    # Check if room is full.
    room = memcache.get(
        get_memcache_key_for_room(self.request.host_url, room_id))
    if room is not None:
      logging.info('Room ' + room_id + ' has state ' + str(room))
      if room.get_occupancy() >= 2:
        logging.info('Room ' + room_id + ' is full')
        self.write_response('full_template.html')
        return
    # Parse out room parameters from request.
    params = get_room_parameters(self.request, room_id, None, None)
    # room_id/room_link will be included in the returned parameters
    # so the client will launch the requested room.
    self.write_response('index_template.html', params)

會使用get函數進行處理,基本應該就是根據房間狀態, 返回狀態,如果放假非空,則輸出房間狀態, 並且如果房間超過2個客戶端,則輸出full_template.html模板。也就是建立房間後,如果房間數大於2個,則會提示房間滿的頁面。可以通過這個來調節輸出房間滿的條件。
其他分析類似

其中compute_page.ComputePage表示的是compute_page.py中的ComputePage類。

基本分析就是如此。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章