Can't determine the usage of url for websocket - websocket

There is a tutorial page I'm following on WebSockets and Django Channels.
Below is the front end code:
var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
var chat_socket = new ReconnectingWebSocket(ws_scheme + '://' + window.location.host + "/chat" + window.location.pathname);
URLs.py
urlpatterns = [
url(r'^$', views.about, name='about'),
url(r'^new/$', views.new_room, name='new_room'),
url(r'^(?P<label>[\w-]{,50})/$', views.chat_room, name='chat_room'),
]
views.py
def chat_room(request, label):
# If the room with the given label doesn't exist, automatically create it
# upon first visit (a la etherpad).
room, created = Room.objects.get_or_create(label=label)
# We want to show the last 50 messages, ordered most-recent-last
messages = reversed(room.messages.order_by('-timestamp')[:50])
return render(request, "chat/room.html", {
'room': room,
'messages': messages,
})
Why are we using the following?
"/chat" + window.location.pathname);
I understand that this URL is the location of the WebSocket server. But how does this URL locate that as we did not specify any such pattern anywhere?

Related

how to make a websocket connection to dynamic url from the javascript?

I have a all_products_page.html(super admin side) where i'm getting products of all the user.
In this page there is a column named 'status'. on which i'm sending an ajax request to approve or unapprove product.
I want whenever super admin approve or unapprove a product a notification to be send to that particular user.
How can i achieve that, as i can only send one room_name.
models.py
#receiver(post_save, sender=BroadcastNotification)
def notification_handler(sender, instance, created,update_fields, **kwargs):
# if seen field is not updated in DB , i.e if message is created or updated then send notifiction
if created or update_fields is None:
channel_layer = get_channel_layer()
# call group_send function to send notifications
async_to_sync(channel_layer.group_send)(
"notification_" + "admin" if not instance.from_admin
else "notification_" + str(instance.notification_receiver_id),
{
'type': 'send_notification' ,
'message': json.dumps(str(instance.id) + ">" + instance.message + ">"
+ instance.notification_link)
}
)
In models.py i'm calling notification on post save of data
consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class NotificationConsumer(AsyncWebsocketConsumer):
async def connect(self):
# get user id of notification receiver
self.room_name = self.scope['path'].split('/')[3]
self.room_group_name = 'notification_%s' % self.room_name
print(self.room_group_name)
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Leave room group
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from room group
async def send_notification(self, event):
message = json.loads(event['message'])
print("msg",message)
# Send message to WebSocket
await self.send(text_data=json.dumps(message))
main.js
const notificationSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/notification/'
+ roomName
+ '/'
);
//-----------------If any message for websocket , append message to dropdown and update badge number----------
notificationSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
console.log(data);
let notif_id = data.split('>')[0];
let msg = data.split('>')[1];
let link = data.split('>')[2];
if(roomName == "admin")
{
document.getElementById(`notifications-dropdown`).innerHTML
= `<a class="dropdown-item notification_msg_drpdwn" msg_id="${notif_id}"
href="${link}" >${msg}</a>` +"</li><hr class='dropdown-divider'>" +
document.getElementById(`notifications-dropdown`).innerHTML;
document.getElementById(`notification-badge`).innerHTML
= parseInt(document.getElementById(`notification-badge`).innerHTML) + 1;
}
else
{
document.getElementById(`notifications-dropdown_${roomName}`).innerHTML
= `<a class="dropdown-item notification_msg_drpdwn" msg_id="${notif_id}"
href="${link}" >${msg}</a>` +"</li><hr class='dropdown-divider'>" +
document.getElementById(`notifications-dropdown_${roomName}`).innerHTML;
document.getElementById(`notification-badge_${roomName}`).innerHTML
= parseInt(document.getElementById(`notification-badge_${roomName}`).innerHTML) + 1;
}
};

websocket handshake fails with django channels

EDIT: correction after #Ken4scholars comment below
I have the following consumer which fails right after connecting
consumers.py
from channels.generic.websocket import AsyncJsonWebsocketConsumer
#...
class ListGeneratedTokensByFileConsumer(AsyncJsonWebsocketConsumer):
stop = False
async def websocket_connect(self,event):
await self.accept()
self.stop = False
async def websocket_receive(self,event):
await self.send_json({"text":"received","accept": True})
await self.send_tokens_list()
async def websocket_disconnect(self,event):
self.stop = True
async def send_tokens_list(self):
some_path = "..."
while self.stop == False:
await asyncio.sleep(2)
the_message = {}
if os.path.isfile("some_file.json")):
with open(os.path.join(some_path ,"some_file.json"),'r') as new_tok:
the_message = json.load(new_tok)
if not the_message:
print("waiting...")
else:
await self.send_json(the_message)
await self.close()
It always throws the error: ERR_CONNECTION:RESEST and the websocket disconnects with code 1006. This might seem familiar to recent changes in django-channels but since I am sending a text once the websocket opens and send a message back from the consumer it should do the trick. Or is there something wrong?
routing.py
url(r'^myapp/sub_path/(?P<pk>\d+)/sub_sub_path/',ListGeneratedTokensByFileConsumer)
and the websocket endpoint in js is:
.js
var loc = window.location;
var wsStart = "ws://";
if (loc.protocol == "https:") {
wsStart = "wss://";
}
var endpoint = wsStart + loc.host + loc.pathname + "sub_sub_path" + "/";
for info, with channels-redis==2.3.2, channels==2.3.0, asgiref==3.2.2, daphne==2.3.0, django==2.0.8
If you see something like in django logs:
WebSocket HANDSHAKING /ws/your_route
WebSocket REJECT /ws/your_route
WebSocket DISCONNECT /ws/your_route
And you wrapped websocket router with AllowedHostsOriginValidator in the asgi.py like:
application = ProtocolTypeRouter({
"http": django_asgi_app,
"websocket": AllowedHostsOriginValidator(
URLRouter(
chat_websocket_urlpatterns
))
})
Then you definetely should check the ALLOWED_HOSTS variable in the settings.py, maybe you forgot to put something in there. In my case it was just because I didn't specify my IP address, only localhost.
This is most likely not that the asker looked for, but I thought it may come handy to someone else, as there is not much info about the django channels in this site.

Geoserver - GetFeature SHAPE-ZIP request - 413 error

I am using Geoserver with an app written with OpenLayers 3. The app can download zipped shapefiles using a WFS service, which works unless I make a large (long URL) request. In that case I get a 413 error in Chrome.
Is there a way I can change this setting so that I can make a longer request to Geoserver (or is the problem something else?
Here is the request:
$('#btnDownloadSHP').click(function (e) {
var tostring = '(' + ids.toString() + ')';
var data = {
service: 'WFS',
version: '1.1.0',
request: 'GetFeature',
typename: 'download_layer',
format_options: "filename:" + shapefileName,
srsname: 'EPSG:3857',
outputFormat: 'SHAPE-ZIP',
CQL_FILTER: "id IN " + tostring
}
var parameters = Object.keys(data).map(function (key) {
return key + '=' + data[key]
}).join('&');
var url = "http://" + servername + "/geoserver/wfs?" + parameters;
//make dummy link and download shapefile
var link = document.createElement("a");
link.download = 'Features';
link.href = url;
link.click();
// }
});
That response would be generated by the server that GeoServer is running on rather than GeoServer itself. So depending on which httpd and/or servlet engine you are using you may be able to fix it there.
But the easy answer is to switch from GET to POST.

Django view with cross-domain Ajax

I have a Django view that I want to integrate with an Ajax call. The call is happening cross domain. I have this code running by itself and making the request cross-domain.
def myview(_request):
response = HttpResponse(json.dumps({"key": "value", "key2": "value"}))
response["Access-Control-Allow-Origin"] = "*"
response["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS"
response["Access-Control-Max-Age"] = "1000"
response["Access-Control-Allow-Headers"] = "*"
return response
I am wondering how to integrate this into my existing view. You will see what I have tried in the code below:
def american_time(request):
#Calling the HTML Source from the URL
sock = urllib.urlopen("http://apps.cbp.gov/bwt/index.asp")
htmlSource = sock.read()
sock.close()
#create a soup object
soup = BeautifulSoup(htmlSource)
#find the tags we need and their content
bridge = soup.findAll('td', limit=215)[194]
tunnel = soup.findAll('td', limit=250)[208]
#new variables to be passed
contents_of_tunnel = tunnel.getText(', ')
contents_of_bridge = bridge.getText(', ')
#check to see if there is a delay for the bridge
if 'no delay' in contents_of_bridge:
time_to_cross_the_bridge = 0
else:
inside_of_bridge = re.split(r', ', contents_of_bridge)
number_inside_of_bridge = inside_of_bridge[1]
list_for_time_to_cross_the_bridge = re.findall(r"\d+", number_inside_of_bridge)
time_to_cross_the_bridge = list_for_time_to_cross_the_bridge[0]
if 'no delay' in contents_of_tunnel:
time_to_cross_the_tunnel = 0
else:
inside_of_tunnel = re.split(r', ', contents_of_tunnel)
number_inside_of_tunnel = inside_of_tunnel[1]
list_for_time_to_cross_the_tunnel = re.findall(r"\d+", number_inside_of_tunnel)
time_to_cross_the_tunnel = list_for_time_to_cross_the_tunnel[0]
response = HttpResponse(json.dumps({"bridge_time": time_to_cross_the_bridge, "tunnel_time": time_to_cross_the_tunnel}))
response["Access-Control-Allow-Origin"] = "*"
response["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS"
response["Access-Control-Max-Age"] = "1000"
response["Access-Control-Allow-Headers"] = "*"
#finally, return as Ajax
return HttpResponse(response)
AJAX:
$.get( "http://localhost:8000/us", function(json){
$('#timeone').html(json.bridge_time + "min delay");
$('#timetwo').html(json.tunnel_time + "min delay");
})
.fail(function(){
alert('We can\'t get data right now! Please try again later.');
})
.done(function(){
alert('Success!');
});
However, I am still getting the message XMLHttpRequest cannot load http://localhost:8000/us. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. in the console. How can I integrate this header into my view?
Try add this middleware.
How to add see documentation https://docs.djangoproject.com/en/dev/topics/http/middleware/

FileUpload with Django

I'm using the ajax-upload code to do a simple AJAX file upload. The issue I'm coming across is the file isn't showing up on the backend after submitting.
The frontend code is pretty basic:
<div id="image_uploader">Upload More Images</div>
<script type="text/javascript" charset="utf-8">
function createUploader(){
var uploader = new qq.FileUploader({
element: document.getElementById('image_uploader'),
action: '/add/image/1',
debug: true,
onSubmit : function () {
progress.show();
},
onComplete : function () {
progress.hide();
},
onCancel : function () {
progress.hide();
},
});
};
createUploader();
</script>
The backend code (currently in progress) is also pretty basic:
def add_image(request, id):
print request
if request.FILES:
return HttpResponse("{success:true}")
else:
return HttpResponse("{success:false, message:'Unable to find FILES}")
For me, using code from Alex Kuhl, request.GET['qqfile'] had the filename and request.read() (in Django 1.3) returned the data.
request.FILES was only used in a scenario that hasn't yet happened for me. I'm using ajax-upload to talk directly to Photologue, and my code looks something like this:
def save_upload( uploaded, filename, raw_data ):
"""
raw_data: if True, upfile is a HttpRequest object with raw post data
as the file, rather than a Django UploadedFile from request.FILES
"""
try:
filename = os.path.normpath(os.path.join(IMAGE_UPLOAD_PATH, filename))
with BufferedWriter( FileIO( filename, "wb" ) ) as dest:
# if the "advanced" upload, read directly from the HTTP request
# with the Django 1.3 functionality
if raw_data:
(dirName, fileName) = os.path.split(filename)
(fileBaseName, fileExtension)=os.path.splitext(fileName)
#
# right here, if fileBaseName is less than n characters, might want to slap on a date just for fun
#
try:
i_can_has_p = Photo.objects.get(title=fileBaseName)
title = fileBaseName + "_" + str(datetime.datetime.now().strftime("%Y%m%dT%H%M%S"))
except Photo.DoesNotExist:
title = fileBaseName
title_slug = slugify(title)
p = Photo(title=title, title_slug=title_slug)
p.image.save(filename,ContentFile(uploaded.read()))
# if not raw, it was a form upload so read in the normal Django chunks fashion
else:
# TODO: figure out when this gets called, make it work to save into a Photo like above
for c in uploaded.chunks( ):
dest.write( c )
except IOError:
# could not open the file most likely
return False
return True
def ajax_upload( request ):
if request.method == "POST":
# AJAX Upload will pass the filename in the querystring if it is the "advanced" ajax upload
if request.is_ajax( ):
# the file is stored raw in the request
upload = request
is_raw = True
try:
filename = request.GET[ 'qqfile' ]
except KeyError:
return HttpResponseBadRequest( "AJAX request not valid" )
# not an ajax upload, so it was the "basic" iframe version with submission via form
else:
is_raw = False
if len( request.FILES ) == 1:
# FILES is a dictionary in Django but Ajax Upload gives the uploaded file an
# ID based on a random number, so it cannot be guessed here in the code.
# Rather than editing Ajax Upload to pass the ID in the querystring, note that
# each upload is a separate request so FILES should only have one entry.
# Thus, we can just grab the first (and only) value in the dict.
upload = request.FILES.values( )[ 0 ]
else:
raise Http404( "Bad Upload" )
filename = upload.name
# save the file
success = save_upload( upload, filename, is_raw )
# let Ajax Upload know whether we saved it or not
ret_json = { 'success': success, }
return HttpResponse( json.dumps( ret_json ) )
In my case, ajax_upload is the function called by ajax's action: parameter
Andrew Valums has now got a django app at git hub

Resources