fanout / django-eventstream

Server-Sent Events for Django
MIT License
638 stars 84 forks source link

Get request object in eventstream #74

Closed Samiddha99 closed 2 years ago

Samiddha99 commented 3 years ago

Using view we can get the user information from request object. But in eventstream there have no request object. So in eventstream how can I get the user information? Suppose, url of an eventstream is "/events/". So when from client device a connection will be made with the event, then this event will only streaming the data related to this user. I can do that by using client's username in eventstream url. I don't want to pass username with url for security reasons.

jkarneges commented 3 years ago

Hi,

The docs are light in details, but determining channels from a request is described here. At the end of that section it says you can do advanced mapping using a channel manager. For an example of a channel manager, see this section.

In the channel manger, you'll want to reimplement get_channels_for_request. You can see the default implementation here. But in your reimplementation you could do anything. And the current request is supplied as an argument.

Samiddha99 commented 3 years ago

I do this -

In myapp.channelmanager.py

from django_eventstream.channelmanager import ChannelManagerBase

class CustomChannelManager(ChannelManagerBase):
    def get_channels_for_request(self, request, view_kwargs):
        if 'format-channels' in view_kwargs:
            channel = str(view_kwargs['format-channels'])
            channel = channel.format(request.user.username)
            return set(channel)
        elif 'channels' in view_kwargs:
            return set(view_kwargs['channels'])
        elif 'channel' in view_kwargs:
            return set([view_kwargs['channel']])
        else:
            return set(request.GET.getlist('channel'))

In settings.py EVENTSTREAM_CHANNELMANAGER_CLASS = 'myapp.channelmanager.CustomChannelManager

In myapp.urls.py

import django_eventstream
urlpatterns += [path('events/', include(django_eventstream.urls), { 'format-channels': ['customuser-{}'] }),]

In asgi.py

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')

application = ProtocolTypeRouter({
    'http': URLRouter([

        url(r'^events/', AuthMiddlewareStack(URLRouter(
            django_eventstream.routing.urlpatterns
        )),{ 'format-channels': ['customuser-{}'] }),

        url(r'', get_asgi_application()),

    ]),
})

But when I go to the url http://127.0.0.1:8000/events/ I am getting the following response -

{
"condition": "bad-request",
"text": "Invalid request: Channel limit exceeded."
}
jkarneges commented 3 years ago

Hi,

I think this code is wrong:

channel = str(view_kwargs['format-channels'])
channel = channel.format(request.user.username)
return set(channel)

Probably it should be something like:

channel = view_kwargs['format-channels'][0]
channel = channel.format(request.user.username)
return set([channel])
Samiddha99 commented 3 years ago

After make changes in myapp.channelmanager.py according to suggestion, the events are loading, i.e. when I go to the url http://127.0.0.1:8000/events/ , the link continually loading, it's not showing anything in the web page (in the browser tab the loading Spiner spinning). I put a print(), in get_channels_for_request() function to check if it works:

channel = view_kwargs['format-channels'][0]
channel = channel.format(request.user.username)
print(channel)
return set([channel])

I noticed that it successfully print the channel name - "customuser-Admin" (I logged in with username Admin). So what to do now?

jkarneges commented 3 years ago

By "go to the url" do you mean you tried to browse to it? That won't really work. You need to connect to the events URL using EventSource in JS.

Samiddha99 commented 3 years ago

To check it with EventSource, I try to send an event to the streaming with send_event('customuser-{}'.format(request.user.username), 'message', 'mydata') from views, and I get NotImplementedError()

jkarneges commented 3 years ago

Ah, try inheriting from DefaultChannelManager rather than ChannelManagerBase.

Samiddha99 commented 2 years ago

Thanks, problem solved