def messages_last(request): if request.method == 'GET': # Get the most recent sent message from the database (empty string by # default), and generate a simple ETag. message = LastMessage.get_only().text etag = '"%s"' % hashlib.md5(message).hexdigest() inm = request.META.get('HTTP_IF_NONE_MATCH') wait = (request.GET.get('wait') == 'true') if inm == etag: # If a matching If-None-Match header was supplied, then return # status 304. resp = HttpResponseNotModified() if wait: # Set the request to hold open as a long-poll, subscribed to # a channel. channel = Channel('messages', prev_id=etag) set_hold_longpoll(request, channel) else: resp = HttpResponse(message + '\n', content_type='text/plain') resp['ETag'] = etag return resp else: return HttpResponseNotAllowed(['GET'])
def item(request, headline_id): h = get_object_or_404(Headline, pk=headline_id) if request.wscontext: ws = request.wscontext if ws.is_opening(): ws.accept() ws.subscribe('headline-%s' % headline_id) while ws.can_recv(): message = ws.recv() if message is None: ws.close() break return HttpResponse() elif request.method == 'GET': if request.META.get('HTTP_ACCEPT') == 'text/event-stream': resp = HttpResponse(content_type='text/event-stream') set_hold_stream(resp, 'headline-%s' % headline_id) return resp else: wait = request.META.get('HTTP_WAIT') if wait: wait = int(wait) if wait < 1: wait = None if wait > 300: wait = 300 inm = request.META.get('HTTP_IF_NONE_MATCH') etag = '"%s"' % calendar.timegm(h.date.utctimetuple()) if inm == etag: resp = HttpResponseNotModified() if wait: set_hold_longpoll(resp, 'headline-%s' % headline_id, timeout=wait) else: resp = _json_response(h.to_data()) resp['ETag'] = etag return resp elif request.method == 'PUT': hdata = json.loads(request.read()) h.type = hdata['type'] h.title = hdata.get('title', '') h.text = hdata.get('text', '') h.save() hdata = h.to_data() hjson = json.dumps(hdata) etag = '"%s"' % calendar.timegm(h.date.utctimetuple()) rheaders = {'ETag': etag} hpretty = json.dumps(hdata, indent=4) + '\n' formats = list() formats.append(HttpResponseFormat(body=hpretty, headers=rheaders)) formats.append(HttpStreamFormat('event: update\ndata: %s\n\n' % hjson)) formats.append(WebSocketMessageFormat(hjson)) publish('headline-%s' % headline_id, formats) resp = _json_response(hdata) resp['ETag'] = etag return resp else: return HttpResponseNotAllowed(['GET', 'PUT'])
def item(request, headline_id): h = get_object_or_404(Headline, pk=headline_id) if request.wscontext: ws = request.wscontext if ws.is_opening(): ws.accept() ws.subscribe(headline_id) while ws.can_recv(): message = ws.recv() if message is None: ws.close() break return HttpResponse() elif request.method == 'GET': if request.META.get('HTTP_ACCEPT') == 'text/event-stream': resp = HttpResponse(content_type='text/event-stream') set_hold_stream(request, headline_id) return resp else: wait = request.META.get('HTTP_WAIT') if wait: wait = int(wait) if wait < 1: wait = None if wait > 300: wait = 300 inm = request.META.get('HTTP_IF_NONE_MATCH') etag = '"%s"' % calendar.timegm(h.date.utctimetuple()) if inm == etag: resp = HttpResponseNotModified() if wait: set_hold_longpoll(request, headline_id, timeout=wait) else: resp = _json_response(h.to_data()) resp['ETag'] = etag return resp elif request.method == 'PUT': hdata = json.loads(request.read()) h.type = hdata['type'] h.title = hdata.get('title', '') h.text = hdata.get('text', '') h.save() hdata = h.to_data() hjson = json.dumps(hdata) etag = '"%s"' % calendar.timegm(h.date.utctimetuple()) rheaders = {'Content-Type': 'application/json', 'ETag': etag} hpretty = json.dumps(hdata, indent=4) + '\n' formats = list() formats.append(HttpResponseFormat(body=hpretty, headers=rheaders)) formats.append(HttpStreamFormat('event: update\ndata: %s\n\n' % hjson)) formats.append(WebSocketMessageFormat(hjson)) publish(headline_id, formats) resp = _json_response(hdata) resp['ETag'] = etag return resp else: return HttpResponseNotAllowed(['GET', 'PUT'])
def todos(request, list_id): if request.method == 'OPTIONS': resp = HttpResponse() resp['Access-Control-Max-Age'] = '3600' return resp if request.method == 'HEAD': last_cursor = TodoItem.get_last_cursor(list_id) resp = HttpResponse() resp['Link'] = _changes_link(list_id, last_cursor.cur) return resp elif request.method == 'GET': stream = request.GET.get('stream') after = request.GET.get('after_change') wait = request.META.get('HTTP_WAIT') if stream: stream = (stream == 'true') if wait: wait = int(wait) if stream: set_hold_stream(request, Channel('todos-%s' % list_id)) return HttpResponse(content_type='text/plain') else: if after: try: items, last_cursor = TodoItem.get_after(list_id, after) except TodoItem.DoesNotExist: return HttpResponseNotFound() else: items, last_cursor = TodoItem.get_all(list_id) resp = _list_response(list_id, items) resp['Link'] = _changes_link(list_id, last_cursor.cur) if len(items) == 0 and wait: set_hold_longpoll(request, Channel('todos-%s' % list_id, prev_id=last_cursor.cur), timeout=wait) return resp elif request.method == 'POST': params = json.loads(request.body) i = TodoItem(list_id=list_id) if 'text' in params: i.text = params['text'] if 'completed' in params: if not isinstance(params['completed'], bool): return HttpResponseBadRequest('completed must be a bool\n', content_type='text/plain') i.completed = params['completed'] try: cursor = i.save() except TodoItem.LimitError: return HttpResponseForbidden('limit reached\n', content_type='text/plain') if cursor.cur != cursor.prev: _publish_item(list_id, i, cursor) resp = _item_response(i, status=201) resp['Location'] = reverse('todos-item', args=[list_id, i.id]) return resp else: return HttpResponseNotAllowed(['HEAD', 'GET', 'POST'])
def process_view(self, request, view_func, view_args, view_kwargs): # require grip middleware assert hasattr(request, 'grip_proxied'), 'GripMiddleware must run before LiveResourceMiddleware' if getattr(view_func, 'live', False): # parse wait header wait = request.META.get('HTTP_WAIT') if wait is not None: try: wait = int(wait) except: return HttpResponseBadRequest('Invalid Wait header specified.\n') if wait < 1: wait = None elif wait > WAIT_MAX: wait = WAIT_MAX resp = view_func(request, *view_args, **view_kwargs) if wait: if not request.grip_proxied: return HttpResponse('Error: Realtime request not supported. Set up Pushpin or Fanout.\n', status=501) if hasattr(resp, 'multi_info'): channels = list() for ri in resp.multi_info: try: channel = channel_object_for_request(request, ri, True) except: return HttpResponse('Resource cannot be used for updates.\n', status=501) channels.append(channel) set_hold_longpoll(resp, channels, timeout=wait) else: ri = get_resourceinfo(canonical_uri(request.path), resp) if ri: try: channel = channel_object_for_request(request, ri, True) except: return HttpResponse('Resource cannot be used for updates.\n', status=501) set_hold_longpoll(resp, channel, timeout=wait) return resp
def items(req, inbox_id): if req.method == 'GET': try: db.inbox_refresh(inbox_id) except redis_ops.InvalidId: return HttpResponseBadRequest('Bad Request: Invalid id\n') except redis_ops.ObjectDoesNotExist: return HttpResponseNotFound('Not Found\n') except: return HttpResponse('Service Unavailable\n', status=503) order = req.GET.get('order') if order and order not in ('created', '-created'): return HttpResponseBadRequest('Bad Request: Invalid order value\n') if not order: order = 'created' imax = req.GET.get('max') if imax: try: imax = int(imax) if imax < 1: raise ValueError('max too small') except: return HttpResponseBadRequest( 'Bad Request: Invalid max value\n') if not imax or imax > 50: imax = 50 since = req.GET.get('since') since_id = None since_cursor = None if since: if since.startswith('id:'): since_id = since[3:] elif since.startswith('cursor:'): since_cursor = since[7:] else: return HttpResponseBadRequest( 'Bad Request: Invalid since value\n') # at the moment, cursor is identical to id item_id = None if since_id: item_id = since_id elif since_cursor: item_id = since_cursor if order == 'created': try: items, last_id = db.inbox_get_items_after( inbox_id, item_id, imax) except redis_ops.InvalidId: return HttpResponseBadRequest('Bad Request: Invalid id\n') except redis_ops.ObjectDoesNotExist: return HttpResponseNotFound('Not Found\n') except: return HttpResponse('Service Unavailable\n', status=503) out = dict() out['last_cursor'] = last_id out_items = list() for i in items: out_items.append( _convert_item( i, not db.request_is_pending(inbox_id, i['id']))) out['items'] = out_items if len(out_items) == 0: set_hold_longpoll( req, Channel(grip_prefix + 'inbox-%s' % inbox_id, last_id)) return HttpResponse(json.dumps(out) + '\n', content_type='application/json') else: # -created try: items, last_id, eof = db.inbox_get_items_before( inbox_id, item_id, imax) except redis_ops.InvalidId: return HttpResponseBadRequest('Bad Request: Invalid id\n') except redis_ops.ObjectDoesNotExist: return HttpResponseNotFound('Not Found\n') except: return HttpResponse('Service Unavailable\n', status=503) out = dict() if not eof and last_id: out['last_cursor'] = last_id out_items = list() for i in items: out_items.append( _convert_item( i, not db.request_is_pending(inbox_id, i['id']))) out['items'] = out_items return HttpResponse(json.dumps(out) + '\n', content_type='application/json') else: return HttpResponseNotAllowed(['GET'])
def hit(req, inbox_id): try: inbox = db.inbox_get(inbox_id) except redis_ops.InvalidId: return HttpResponseBadRequest('Bad Request: Invalid id\n') except redis_ops.ObjectDoesNotExist: return HttpResponseNotFound('Not Found\n') except: return HttpResponse('Service Unavailable\n', status=503) response_mode = inbox.get('response_mode') if not response_mode: response_mode = 'auto' # pubsubhubbub verify request? hub_challenge = req.GET.get('hub.challenge') if response_mode == 'wait' or (response_mode == 'wait-verify' and hub_challenge): respond_now = False else: respond_now = True item = _req_to_item(req) if hub_challenge: item['type'] = 'hub-verify' else: item['type'] = 'normal' try: item_id, prev_id, item_created = db.inbox_append_item(inbox_id, item) db.inbox_clear_expired_items(inbox_id) except redis_ops.InvalidId: return HttpResponseBadRequest('Bad Request: Invalid id\n') except redis_ops.ObjectDoesNotExist: return HttpResponseNotFound('Not Found\n') except: return HttpResponse('Service Unavailable\n', status=503) item['id'] = item_id item['created'] = item_created item = _convert_item(item, respond_now) hr_headers = dict() hr_headers['Content-Type'] = 'application/json' hr = dict() hr['last_cursor'] = item_id hr['items'] = [item] hr_body = json.dumps(hr) + '\n' hs_body = json.dumps(item) + '\n' formats = list() formats.append(HttpResponseFormat(headers=hr_headers, body=hr_body)) formats.append(HttpStreamFormat(hs_body)) publish(grip_prefix + 'inbox-%s' % inbox_id, formats, id=item_id, prev_id=prev_id) if respond_now: if hub_challenge: return HttpResponse(hub_challenge) else: return HttpResponse('Ok\n') else: # wait for the user to respond db.request_add_pending(inbox_id, item_id) set_hold_longpoll(req, grip_prefix + 'wait-%s-%s' % (inbox_id, item_id)) return HttpResponse('Service Unavailable\n', status=503, content_type='text/html')
def items(req, inbox_id): if req.method == 'GET': try: db.inbox_refresh(inbox_id) except redis_ops.InvalidId: return HttpResponseBadRequest('Bad Request: Invalid id\n') except redis_ops.ObjectDoesNotExist: return HttpResponseNotFound('Not Found\n') except: return HttpResponse('Service Unavailable\n', status=503) order = req.GET.get('order') if order and order not in ('created', '-created'): return HttpResponseBadRequest('Bad Request: Invalid order value\n') if not order: order = 'created' imax = req.GET.get('max') if imax: try: imax = int(imax) if imax < 1: raise ValueError('max too small') except: return HttpResponseBadRequest('Bad Request: Invalid max value\n') if not imax or imax > 50: imax = 50 since = req.GET.get('since') since_id = None since_cursor = None if since: if since.startswith('id:'): since_id = since[3:] elif since.startswith('cursor:'): since_cursor = since[7:] else: return HttpResponseBadRequest('Bad Request: Invalid since value\n') # at the moment, cursor is identical to id item_id = None if since_id: item_id = since_id elif since_cursor: item_id = since_cursor if order == 'created': try: items, last_id = db.inbox_get_items_after(inbox_id, item_id, imax) except redis_ops.InvalidId: return HttpResponseBadRequest('Bad Request: Invalid id\n') except redis_ops.ObjectDoesNotExist: return HttpResponseNotFound('Not Found\n') except: return HttpResponse('Service Unavailable\n', status=503) out = dict() out['last_cursor'] = last_id out_items = list() for i in items: out_items.append(_convert_item(i, not db.request_is_pending(inbox_id, i['id']))) out['items'] = out_items if len(out_items) == 0: set_hold_longpoll(req, Channel(grip_prefix + 'inbox-%s' % inbox_id, last_id)) return HttpResponse(json.dumps(out) + '\n', content_type='application/json') else: # -created try: items, last_id, eof = db.inbox_get_items_before(inbox_id, item_id, imax) except redis_ops.InvalidId: return HttpResponseBadRequest('Bad Request: Invalid id\n') except redis_ops.ObjectDoesNotExist: return HttpResponseNotFound('Not Found\n') except: return HttpResponse('Service Unavailable\n', status=503) out = dict() if not eof and last_id: out['last_cursor'] = last_id out_items = list() for i in items: out_items.append(_convert_item(i, not db.request_is_pending(inbox_id, i['id']))) out['items'] = out_items return HttpResponse(json.dumps(out) + '\n', content_type='application/json') else: return HttpResponseNotAllowed(['GET'])
def hit(req, inbox_id): if len(req.grip.last) > 0: for channel, last_id in req.grip.last.iteritems(): break set_hold_longpoll(req, Channel(channel, last_id)) return HttpResponse('Service Unavailable\n', status=503, content_type='text/html') try: inbox = db.inbox_get(inbox_id) except redis_ops.InvalidId: return HttpResponseBadRequest('Bad Request: Invalid id\n') except redis_ops.ObjectDoesNotExist: return HttpResponseNotFound('Not Found\n') except: return HttpResponse('Service Unavailable\n', status=503) response_mode = inbox.get('response_mode') if not response_mode: response_mode = 'auto' # pubsubhubbub verify request? hub_challenge = req.GET.get('hub.challenge') if response_mode == 'wait' or (response_mode == 'wait-verify' and hub_challenge): respond_now = False else: respond_now = True item = _req_to_item(req) if hub_challenge: item['type'] = 'hub-verify' else: item['type'] = 'normal' try: item_id, prev_id, item_created = db.inbox_append_item(inbox_id, item) db.inbox_clear_expired_items(inbox_id) except redis_ops.InvalidId: return HttpResponseBadRequest('Bad Request: Invalid id\n') except redis_ops.ObjectDoesNotExist: return HttpResponseNotFound('Not Found\n') except: return HttpResponse('Service Unavailable\n', status=503) item['id'] = item_id item['created'] = item_created item = _convert_item(item, respond_now) hr_headers = dict() hr_headers['Content-Type'] = 'application/json' hr = dict() hr['last_cursor'] = item_id hr['items'] = [item] hr_body = json.dumps(hr) + '\n' hs_body = json.dumps(item) + '\n' formats = list() formats.append(HttpResponseFormat(headers=hr_headers, body=hr_body)) formats.append(HttpStreamFormat(hs_body)) publish(grip_prefix + 'inbox-%s' % inbox_id, formats, id=item_id, prev_id=prev_id) if respond_now: if hub_challenge: return HttpResponse(hub_challenge) else: return HttpResponse('Ok\n') else: # wait for the user to respond db.request_add_pending(inbox_id, item_id) set_hold_longpoll(req, Channel(grip_prefix + 'wait-%s-%s' % (inbox_id, item_id), '0')) return HttpResponse('Service Unavailable\n', status=503, content_type='text/html')