WebServer can be subclassed, but is not work for me.

20 views
Skip to first unread message

Bright Pan

unread,
Jul 29, 2018, 10:02:17 AM7/29/18
to nameko-dev
hi, 
i subclass WebServer for my socket server,  but Error for me.


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Created by jason at 15/12/2017

from jinja2 import Template
from nameko.extensions import DependencyProvider
from nameko.timer import timer
from nameko.web.server import WebServer as BaseWebServer
from nameko.web.handlers import HttpRequestHandler as BaseHttpRequestHandler
from nameko.web.websocket import WebSocketHubProvider, rpc
from werkzeug.wrappers import Response


TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
<style>
#console{
padding:5px;
border:1px solid black;
}
#console p {
margin:0;
}
.event {
color:#999;
}
.warning{
color: orange;
}
</style>
<title>Nameko Websocket Test</title>
</head>
<body>
<div id="wrapper">
<h1>Nameko Websocket Test</h1>
<button id="disconnect">Disconnect</button>
<div id="container">
<div id="console">
</div>
</div>
<script type="text/javascript">
function connect(){
var socket;
var host = "ws://{{host}}:{{port}}/ws";
try{
var socket = new WebSocket(host);
message('<p class="event">Socket Status: '+socket.readyState);
socket.onopen = function(){
message('<p class="event">Socket Status: '+socket.readyState+' (open)');
subscribe();
}
socket.onmessage = function(msg){
message('<p class="message">Received: '+msg.data);
}
socket.onclose = function(){
message('<p class="event">Socket Status: '+socket.readyState+' (Closed)');
}
} catch(exception){
message('<p>Error'+exception);
}
function subscribe() {
try{
var json_msg = `{
"method": "subscribe",
"data": { "a": "1"}
}`;
socket.send(json_msg);
message('<p class="event">Sent: '+text)
} catch(exception){
message('<p class="warning">');
}
}
function message(msg){
$('#console').append(msg+'</p>');
}
$('#disconnect').click(function(){
socket.close();
});
}
$(document).ready(function() {
if(!("WebSocket" in window)){
$('<p>This demo requires browser websocket support</p>').appendTo('#container');
return
}
connect();
});
</script>
</body>
</html>
"""


class Config(DependencyProvider):
def get_dependency(self, worker_ctx):
return self.container.config


class ContainerIdentifier(DependencyProvider):
def get_dependency(self, worker_ctx):
return id(self.container)


class WebServer(BaseWebServer):

def context_data_from_headers(self, request):
context_data = super().context_data_from_headers(request)
return context_data


class HttpRequestHandler(BaseHttpRequestHandler):
server = WebServer()


http = HttpRequestHandler.decorator


class WebsocketService(object):
name = "websockets"

container_id = ContainerIdentifier()
websocket_hub = WebSocketHubProvider()
config = Config()

@http('GET', '/')
def home(self, request):
host = self.config.get('PUBLIC_HOST', 'localhost')
port = self.config.get('PUBLIC_PORT', '8000')

payload = Template(TEMPLATE).render({'host': host, 'port': port})
return Response(payload, content_type="text/html")

@rpc
def subscribe(self, socket_id, a):
self.websocket_hub.subscribe(socket_id, 'test_channel')
print(type(a))
return 'subscribed to test_channel' + a

@timer(10)
def ping(self):
self.websocket_hub.broadcast('test_channel', 'ping', {
'value': "ping from {}".format(self.container_id),
})


the response is 
Not Found

The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.


if i use the base Webserver ,it work for me, Why?


modify

http = HttpRequestHandler.decorator

to 

http = BaseHttpRequestHandler.decorator


the response is fine.

Socket Status: 0



Socket Status: 1 (open)



Received: {"type": "event", "event": "connected", "data": {"socket_id": "2cc07cde-d15e-487d-bd98-0cca1d254e8d"}}

Received: {"type": "result", "success": true, "data": "subscribed to test_channel1", "correlation_id": null}

Received: {"type": "event", "event": "ping", "data": {"value": "ping from 4380437064"}}

Received: {"type": "event", "event": "ping", "data": {"value": "ping from 4380437064"}}

Received: {"type": "event", "event": "ping", "data": {"value": "ping from 4380437064"}}

Received: {"type": "event", "event": "ping", "data": {"value": "ping from 4380437064"}}


Haddleton, Bob (Nokia - US/Naperville)

unread,
Jul 29, 2018, 10:06:38 AM7/29/18
to Bright Pan, nameko-dev
Have you tried adding an __init__ method to your WebServer class and call the super().__init__() method for the superclass?

Bob
--
You received this message because you are subscribed to the Google Groups "nameko-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nameko-dev+...@googlegroups.com.
To post to this group, send email to namek...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/nameko-dev/30d1cfff-458b-4401-bb05-8617662d16ab%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Bright Pan

unread,
Jul 29, 2018, 10:47:31 AM7/29/18
to nameko-dev
hi, i try call super().__init__()

class WebServer(BaseWebServer):

def context_data_from_headers(self, request):
context_data = super().context_data_from_headers(request)
return context_data

def __init__(self):
super().__init__()


class HttpRequestHandler(BaseHttpRequestHandler):
server = WebServer()

def __init__(self, method, url, **kwargs):
super().__init__(method, url, **kwargs)


but is doesn't  work, the response is 404 Not Found.
To post to this group, send email to name...@googlegroups.com.

David Szotten

unread,
Jul 29, 2018, 1:32:02 PM7/29/18
to nameko-dev
Hi,

The issue is that the `WebServer` is a `SharedExtension` (shared by eg http and websocket decorators). Unfortunately the docs are lacking in this area, but the way sharing is tracked at the moment is using the type of the shared extension (your issue is making me wondering if we need a new approach. 

To make this work you need to override the sharing key on your subclass:

```
class WebServer(BaseWebServer):
    @property
    def sharing_key(self):
        return BaseWebServer

    def context_data_from_headers(self, request):
        ...

```

Best,
David

David Szotten

unread,
Jul 29, 2018, 3:03:27 PM7/29/18
to nameko-dev
to expand a little: what was happening was that your http and websocket rpc entrypoints were using different web servers. they were both bound to the same address but one would arbitrarily win and not know hot to route calls to entrypoints on the other server

we don't get a conflict when the second server binds to the same address because we (eventlet's default) set SO_REUSEPORT. Not sure yet if that's a correct choice or not, but it's unfortunate in this case since there's no error

best,
david

Bright Pan

unread,
Jul 29, 2018, 11:37:41 PM7/29/18
to nameko-dev
thanks, david

now, it works for me.

i agree with you advice, so i use http and websocket rpc entrypoints in different web server

best,
bright


在 2018年7月30日星期一 UTC+8上午1:32:02,David Szotten写道:
Reply all
Reply to author
Forward
0 new messages