Django Channels - Handshaking & Connect, but websocket.connect function is not executed - websocket

I'm working on a django project with channels involved in different apps. The first app (receiving data from a sensor) has it's own consumer and routing, as well as the second one (updates a list of logged in users).
Within the first app everything works fine.
In the second app the handshake is completed and the connection is established, but the function, that is linked to websocket.receive is not executed.
from channels.routing import route, route_class
from channels.staticfiles import StaticFilesConsumer
from users.consumer import ws_connect, ws_disconnect
channel_routing = [
route('websocket.connect', ws_connect, path=r'^/users/lobby/'),
...
]
and the ws_connect
import json
from channels import Group
from channels.handler import AsgiHandler
from channels.auth import channel_session_user,
channel_session_user_from_http, channel_session
#channel_session_user_from_http
def ws_connect(message):
print('test')
The print('test') of ws_connect is never executed. Additionally it even doesn't matter what url ending I'm using in javascript.
var ws = new WebSocket('ws://127.0.0.1:8000/users/lobby/');
ws.onopen = function() {
console.log('connect');
ws.send('connect');
}
The ws of the javascript will connect with .../users/lobby/ or .../lobby/ of .../users/.
Thanks for any hints on this!

Since i apparently need 50 reputation to make a comment i'm just gonna make an answer instead even tho i am not sure this is the solution for you.
I had the same exact problem when copying parts of the the github multichat project made by the guy whom made channels.
My issue was apparently that i hade miss spelled the routing with a slight misstake and therefor it didn't call the correct function i had setup for that routing.
So my advice is that you trippel check the routing everywhere to see if you've messed up. I personally only checked my APP routing when error checking but it was in my project folder i had messed upp my routing.
Another thing that might be cauzing this issue is that you only have a routing in your app, but not in the main folder. In that case you need to include the other app routing with the path you want for it just like a view:
from channels import include
channel_routing = [
include("crypto_chat.routing.websocket_routing", path=r"^/chat/stream/$"),
include("crypto_chat.routing.chat_routing"),
]
App routing:
from channels import route
from .consumers import ws_connect, ws_receive, ws_disconnect, user_offline, user_online, chat_send
websocket_routing = [
route("websocket.connect", ws_connect),
route("websocket.receive", ws_receive),
route("websocket.disconnect", ws_disconnect),
]
chat_routing = [
route("chat.receive", chat_send, command="^send$"),
route("chat.receive", user_online, command="^online$"),
route("chat.receive",user_offline, command="^offline$"),
]
If that doesnt help then i suggest you head over to the github channel page for examples and compare the two. Keep in mind tho that the project is probably made from an erlier version of channels (and maybe django aswell).
https://github.com/andrewgodwin/channels-examples
Hope it helps and as i said i would have made a comment but i can't since of my rep apparently...

Related

LiveQuery does not work, if there is no ParseConnectivityProvider provided

Racking my brains over this.
I cannot get past this issue, my code is producing this error:
LiveQuery does not work, if there is no ParseConnectivityProvider provided.
I tried playing around with the liveQueryURL and no luck. The flutter docs have no concrete example on how to implement this url from the server. I assume from the javaScript video and docs that it's my custom subdomain I created such as customdomain.b4a.io which makes the final url 'wss://customdomain.b4a.io'.
I looked into "connectivityProvider:" arg for the Parse().initialize but found nothing concrete on implementing this.
This is a dart demo project only. Any help or ideas much appreciated!
EDIT: This post does not solve my problem at all. It's also very old.
Is it possible this isn't working because this is a dart program rather than flutter? Wouldn't imagine this being the case...
Code:
import 'package:parse_server_sdk/parse_server_sdk.dart';
Future<void> main(List<String> arguments) async {
final keyApplicationId = 'XXX';
final keyClientKey = 'XXX';
final keyParseServerUrl = 'https://parseapi.back4app.com';
final liveQueryURL = 'wss://XXX.b4a.io';
await Parse().initialize(
keyApplicationId,
keyParseServerUrl,
clientKey: keyClientKey,
liveQueryUrl: liveQueryURL,
autoSendSessionId: true,
debug: true,
);
final LiveQuery liveQuery = LiveQuery();
QueryBuilder<ParseObject> query = QueryBuilder<ParseObject>(ParseObject('Color'));
Subscription subscription = await liveQuery.client.subscribe(query);
subscription.on(LiveQueryEvent.create, (value) {
print('Object: ' + value['color']);
print((value as ParseObject).get('color'));
});
}
From https://github.com/parse-community/Parse-SDK-Flutter/issues/543#issuecomment-912783019
please provide a custom ParseConnectivityProvider (connectivityProvider in Parse().initialize).
In case you can assume your device has always internet access, the implementation should be as simple as this:
class CustomParseConnectivityProvider extends ParseConnectivityProvider{
Future<ParseConnectivityResult> checkConnectivity() => ParseConnectivityResult.wifi;
Stream<ParseConnectivityResult> get connectivityStream => Stream<ParseConnectivityResult>.empty();
}
(Not tested and typed on a smartphone.)
Unfortunately parse live query in flutter dose not work with https server url. I faced this problem before and it mades me crazy! What I did was in the backend side of parse server, provide both http and https servers. And In client side in flutter just connect to the http server for live queries!
And that works fine 😉

Workbox cache group is not correct

I'm using workbox-webpack-plugin v5 (the latest) with InjectManifest plugin. The following is my service worker source file:
import { CacheableResponsePlugin } from 'workbox-cacheable-response';
import { clientsClaim, setCacheNameDetails, skipWaiting } from 'workbox-core';
import { ExpirationPlugin } from 'workbox-expiration';
import {
cleanupOutdatedCaches,
createHandlerBoundToURL,
precacheAndRoute,
} from 'workbox-precaching';
import { NavigationRoute, registerRoute, setCatchHandler } from 'workbox-routing';
import { CacheFirst, NetworkOnly, StaleWhileRevalidate } from 'workbox-strategies';
setCacheNameDetails({
precache: 'install-time',
prefix: 'app-precache',
runtime: 'run-time',
suffix: 'v1',
});
cleanupOutdatedCaches();
clientsClaim();
skipWaiting();
precacheAndRoute(self.__WB_MANIFEST);
precacheAndRoute([{ url: '/app-shell.html', revision: 'html-cache-1' }], {
cleanUrls: false,
});
const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler);
registerRoute(navigationRoute);
registerRoute(
/.*\.css/,
new CacheFirst({
cacheName: 'css-cache-v1',
})
);
registerRoute(
/^https:\/\/fonts\.(?:googleapis|gstatic)\.com/,
new CacheFirst({
cacheName: 'google-fonts-cache-v1',
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
}),
new ExpirationPlugin({
maxAgeSeconds: 60 * 60 * 24 * 365,
maxEntries: 30,
}),
],
})
);
registerRoute(
/.*\.js/,
new StaleWhileRevalidate({
cacheName: 'js-cache-v1',
})
);
setCatchHandler(new NetworkOnly());
I have the following questions/problems:
Cache group is not correct. Everything except google fonts is under workbox-precache-v2 or app-precache-install-time-v1 cache group, not individual cache groups such as css-cache-v1, js-cache-v1. However, 1 in 20 times, it shows correct cache group, and I just can't figure out why.
Google font shows from memory cache. Is it correct? It works fine in offline, but what will happen if the user closes the browser/machine and comes back in offline mode?
Is '/app-shell.html' usage correct? It's an express backend app with * as the wild card for all routes, and React Router handles the routing. Functionally, it's working fine offline. I don't have any app-shell.html page.
Thanks for your help.
Cache group is not correct. Everything except google fonts is under workbox-precache-v2 or app-precache-install-time-v1 cache group, not individual cache groups such as css-cache-v1, js-cache-v1. However, 1 in 20 times, it shows correct cache group, and I just can't figure out why.
It depends on what's in your precache manifest (i.e. what self.__WB_MANIFEST gets replaced with during your webpack build).
For example, let's say you have a file generated by webpack called bundle.js, and that file ends up in your precache manifest. Based on your service worker code, that file will end up in a cached called app-precache-install-time-v1—even though it also matches your runtime route with the cache js-cache-v1.
The reason is because your precache route is registered before you runtime route, so your precaching logic will handle that request rather than your runtime caching logic.
Google font shows from memory cache. Is it correct? It works fine in offline, but what will happen if the user closes the browser/machine and comes back in offline mode?
I believe this means the request is not being handled by the service worker, but you can check the workbox logs in the developer console to verify (and see why not).
Alternatively, you could update your code to use a custom handler that just logs whether it's running like so:
registerRoute(
/^https:\/\/fonts\.(?:googleapis|gstatic)\.com/,
({request}) => {
// Log to make sure this function is being called...
console.log(request.url);
return fetch(request);
}
);
Is '/app-shell.html' usage correct? It's an express backend app with * as the wild card for all routes, and React Router handles the routing. Functionally, it's working fine offline. I don't have any app-shell.html page.
Does your express route respond with a file called app-shell.html? If so, then you'd probably want your precache revision to be a hash of the file itself (rather than revision: 'html-cache-1'). What you have right now should work, but the risk is you'll change the contents of app-shell.html, deploy a new version of your app, but your users will still see the old version because you forgot up update revision: 'html-cache-1'. In general it's best to use revisions generated as part of your build step.

Use Dash with websockets

What is the best way to use Dash with Websockets to build a real-time dashboard ? I would like to update a graph everytime a message is received but the only thing I've found is calling the callback every x seconds like the example below.
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_daq as daq
from dash.dependencies import Input, Output
import plotly
import plotly.graph_objs as go
from websocket import create_connection
from tinydb import TinyDB, Query
import json
import ssl
# Setting up the websocket and the necessary web handles
ws = create_connection(address, sslopt={"cert_reqs": ssl.CERT_NONE})
app = dash.Dash(__name__)
app.layout = html.Div(
[
dcc.Graph(id='live-graph', animate=True),
dcc.Interval(
id='graph-update',
interval=1*1000,
n_intervals=0)
]
)
#app.callback(Output('live-graph', 'figure'),
[Input('graph-update', 'n_intervals')])
def update_graph_live(n):
message = ws.recv()
x=message.get('data1')
y=message.get('data2')
.....
fig = go.Figure(
data = [go.Bar(x=x,y=y)],
layout=go.Layout(
title=go.layout.Title(text="Bar Chart")
)
)
)
return fig
if __name__ == '__main__':
app.run_server(debug=True)
Is there a way to trigger the callback everytime a message is received (maybe storing them in a database before) ?
This forum post describes a method to use websocket callbacks with Dash:
https://community.plot.ly/t/triggering-callback-from-within-python/23321/6
Update
Tried it, it works well. Environment is Windows 10 x64 + Python 3.7.
To test, download the .tar.gz file and run python usage.py. It will complain about some missing packages, install these. Might have to edit the address from 0.0.0.0 to 127.0.0.1 in usage.py. Browse to http://127.0.0.1:5000 to see the results. If I had more time, I'd put this example up on GitHub (ping me if you're having trouble getting it to work, or the original gets lost).
I had two separate servers: one for dash, the other one as a socket server. They are running on different ports. On receiving a message, I edited a common json file to share information to dash's callback. That's how I did it.

Serving files with Echo

I'm trying to serve multiple files with Echo, but it doesn't work every time.
The api code looks like this:
package main
import (
"github.com/labstack/echo"
"net/http"
)
func main() {
e := echo.New();
e.GET("/", home);
e.File("/data1", "assets/data1.csv");
e.File("/data2", "assets/data2.csv");
e.Logger.Fatal(e.Start(":4243"));
}
func home(c echo.Context) error {
return c.String(http.StatusOK, "Are you lost?");
}
To be precise, it does work for the very first file fetching, but then keeps failing for any subsequent calls (be them file fetching or more "classic" calls). The error message is a tad different for each browser:
In Chrome:
SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': 'Bearer {the_entire_content_of_the_first_fetched_file}' is not a valid HTTP header field value.
In Firefox:
SyntaxError: An invalid or illegal string was specified
In Edge, simply:
SyntaxError
Tried activating CORS, nothing changed.
Looks to work pretty well with Postman. Maybe it's a problem with how I do fetch my data in my application?
If you need perhaps a bit more information, this thread is directly related to my previous one (Vuejs with axios request in vuex store: can't make more than one request, why?), but I didn't want to mix them up, as I don't know yet if I'm mistaken in my Vue code or my Echo one...
If you would like to delivery files from certain directory. You can do following ways:
e.Use(middleware.Static("/path/to/directory"))
OR
fs := http.FileServer(http.Dir("/path/to/directory"))
e.GET("/assets/*", echo.WrapHandler(http.StripPrefix("/assets/", fs)))
Just Add default CORS Middleware, i just test and it's work fine even i using difference domain.
import this package from echo framework: "github.com/labstack/echo/middleware"
and Add this default CORS config befor your route:
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{"*"},
AllowMethods: []string{echo.GET, echo.PUT, echo.POST, echo.DELETE},
}))
Welp, seems it was my application's fault all along! My Echo api seems fine... for now!
If someone has the same problem, perhaps this Vuejs with axios request in vuex store: can't make more than one request, why? will help.

ChemDoodle Ajax Incompatibility with Pollen.js

I'm trying to use iChemLabs cloud services from a html5 web worker. Normally the cloudservices requires jQuery but I can't import that into a web worker so I'm using Pollen instead with a ChemDoodle Web Components library with which I have stripped out the document-related things.
jQuery.Hive.Pollen provides a nice ajax function very similar to jQuery, but I can't seem to get it to work at all. I know this problem will be tricky to solve considering that Access-control-headers need to be set to allow any of you to actually find the solution. However, I'm a beginning javascript programmer and I was wondering if my two weeks of frustration is actually a small difference. I am trying to invoke the following function:
var cloudmolecule;
ChemDoodle.iChemLabs.readSMILES('N1(C)C(=O)N(C)C(C(=C1N1)N(C=1)C)=O', function(mol){
cloudmolecule = mol;
});
Here is a link to the library code I am using, see the 'q.ajax' call and substitute jQuery = q for p = q (p is for pollen) in that block of code.
Right now I'm just trying to get the ajax call to work in an ordinary block of javascript with the plan to migrate to a web worker later.
If anybody could point out the problem to me I would be extremely grateful.
solved! turns out iChemLabs rejects these two extra headers that pollen creates:
_xhr.setRequestHeader("X-Requested-With", "Worker-XMLHttpRequest");
_xhr.setRequestHeader("X-Worker-Hive", "Pollen-JS" );
Simply comment them out
Also, Pollen ajax seems to return a JSON object containing the data in JSON format AND as a string, so do
o = JSON.parse(data.string)//data is the parameter to the callback function
The reduced ChemDoodle library (without document-related methods) will work like a charm with pollen ajax.

Resources