DjangoChannelsGraphqlWs icon indicating copy to clipboard operation
DjangoChannelsGraphqlWs copied to clipboard

Initial payload

Open AndreyMZ opened this issue 2 years ago • 3 comments

This pull request adds two features:

  1. ~~Per-operation context - allows sharing any data between different calls to Subscription.publish for the same subscription (and the same connection).~~
  2. Initial payload - allows sending an arbitrary "initial" response to a client as soon as it is subscribed (before any call to Subscription.broadcast).

I use them like so (in schema.py):

from __future__ import annotations

from typing import Optional

import channels_graphql_ws
import graphene
from channels_graphql_ws.dict_as_object import DictAsObject
from graphene import ResolveInfo

from .task import Task

class TaskLogChanged(channels_graphql_ws.Subscription):
    class Arguments:
        id = graphene.Argument(graphene.NonNull(graphene.ID))

    content = graphene.Field(graphene.NonNull(graphene.List(graphene.NonNull(graphene.String))))
    begin = graphene.Field(graphene.NonNull(graphene.Int))
    end = graphene.Field(graphene.NonNull(graphene.Int))

    Payload = type(None)

    initial_payload: Payload = None

    @staticmethod
    def subscribe(root: None, info: ResolveInfo, id: str) -> Optional[list[str]]:
        task = Task(id)
        return [task.uuid]

    @classmethod
    def trigger(cls, task: Task) -> None:
        cls.broadcast_sync(group=task.uuid, payload=None)
        
    @classmethod
    async def trigger_async(cls, task: Task) -> None:
        await cls.broadcast_async(group=task.uuid, payload=None)

    @staticmethod
    def publish(payload: None, info: ResolveInfo, id: str) -> Optional[TaskLogChanged]:
        assert isinstance(info.context, DictAsObject)
        try:
            saved_cursor = info.context['cursor']
        except KeyError:
            saved_cursor = 0 
        
        task = Task(id)
        content, new_cursor = task.get_log(saved_cursor)

        if new_cursor == saved_cursor:
            assert len(list(content)) == 0
            return None # Skip this publication.
        else:
            info.context['cursor'] = new_cursor
            return TaskLogChanged(content=content, begin=saved_cursor, end=new_cursor)

AndreyMZ avatar Apr 12 '22 03:04 AndreyMZ

@stmarkevich @sergey-komissarov @prokher is there something preventing this pull request from being merged? I'm eagerly waiting for the initial payload feature to become available. :pray:

fdev avatar May 28 '22 17:05 fdev