Skip to content

Commit 1378236

Browse files
committed
Deploying websockets
2 parents b76b389 + bb655a2 commit 1378236

77 files changed

Lines changed: 2102 additions & 696 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/Concepts/
22
/dist/
3+
/mopidy_spotmop/services/users/users/json
34
*.orig
45
@eaDir
56
Thumbs.db

.htaccess

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Redirect 301 /index.html /src/index.html

mopidy_spotmop/__init__.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,25 @@
33
import logging
44
import os
55
import tornado.web
6+
import tornado.websocket
7+
import json
68
#import mem
79

810
#from services.sync import sync
9-
from services.upgrade import upgrade
11+
from services.upgrade import upgrade
12+
from services.pusher import pusher
1013

1114
#from services.queuemanager import core as QueueManagerCore
1215
#from services.queuemanager import frontend
1316
#from services.queuemanager import requesthandler as QueueManagerRequestHandler
1417

1518
from mopidy import config, ext
1619

17-
__version__ = '2.4.11'
20+
__version__ = '2.5.1'
1821
__ext_name__ = 'spotmop'
1922
__verbosemode__ = False
2023

21-
logger = logging.getLogger(__ext_name__)
24+
logger = logging.getLogger(__name__)
2225

2326
class SpotmopExtension(ext.Extension):
2427
dist_name = 'Mopidy-Spotmop'
@@ -32,6 +35,8 @@ def get_default_config(self):
3235
def get_config_schema(self):
3336
schema = super(SpotmopExtension, self).get_config_schema()
3437
schema['debug'] = config.Boolean()
38+
schema['pusherport'] = config.String()
39+
schema['pusherclientmap'] = config.String()
3540
return schema
3641

3742
def setup(self, registry):
@@ -49,23 +54,27 @@ def setup(self, registry):
4954
'factory': spotmop_client_factory
5055
})
5156

52-
logger.info('Setup Spotmop')
53-
57+
logger.info('Starting Spotmop web client')
5458

5559
def spotmop_client_factory(config, core):
5660

5761
# TODO create minified version of the project for production (or use Bower or Grunt for building??)
5862
environment = 'dev' if config.get(__ext_name__)['debug'] is True else 'prod'
5963
spotmoppath = os.path.join( os.path.dirname(__file__), 'static')
64+
65+
# PUSHER: TODO: need to fire this up from within the PusherHandler class... somehow
66+
pusherport = str(config['spotmop']['pusherport'])
67+
application = tornado.web.Application([
68+
('/pusher', pusher.PusherHandler),
69+
])
70+
application.listen(pusherport)
71+
logger.info( 'Pusher server running on []:'+ str(pusherport) )
6072

6173
return [
6274
('/upgrade', upgrade.UpgradeRequestHandler, {'core': core, 'config': config, 'version': __version__ }),
75+
('/pusher/([^/]+)', pusher.PusherRequestHandler, {'core': core, 'config': config, 'version': __version__ }),
6376
(r'/(.*)', tornado.web.StaticFileHandler, {
6477
"path": spotmoppath,
6578
"default_filename": "index.html"
66-
})
67-
]
68-
69-
70-
71-
79+
}),
80+
]

mopidy_spotmop/ext.conf

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
[spotmop]
22
enabled = true
3-
debug = false
3+
debug = false
4+
pusherport = 6681
5+
pusherclientmap = [{"ip":"192.168.0.152","name":"James"},{"ip":"192.168.0.139","name":"Dev server"},{"ip":"192.168.0.118","name":"Jeremy"}]

mopidy_spotmop/services/pusher/__init__.py

Whitespace-only changes.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import os
2+
import cgi
3+
import tornado.web
4+
5+
from tornado.escape import json_encode,json_decode
6+
from mopidy import config, ext
7+
import subprocess
8+
9+
class IdentifyRequestHandler(tornado.web.RequestHandler):
10+
11+
def set_default_headers(self):
12+
self.set_header("Access-Control-Allow-Origin", "*")
13+
14+
def initialize(self, core, config, version):
15+
self.core = core
16+
self.config = config
17+
self.version = version
18+
19+
def get(self):
20+
ip = self.request.remote_ip
21+
self.write(json_encode({'ip': ip}))
22+
23+
def spotmop_identify_factory(config, core):
24+
return [
25+
('/', IdentifyRequestHandler, {'core': core, 'config': config})
26+
]
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>WebSockets Client</title>
5+
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
6+
</head>
7+
<body>
8+
Enter text to send to the websocket server:
9+
<div id="send">
10+
<strong id="status">loading</strong>
11+
<input type="text" id="name" value="" />
12+
<input type="button" id="notify" value="notify"/>
13+
</div>
14+
<div id="output"></div>
15+
</body>
16+
</html>
17+
<script>
18+
19+
jQuery(function($){
20+
21+
if (!("WebSocket" in window)) {
22+
alert("Your browser does not support web sockets");
23+
}else{
24+
setup();
25+
}
26+
27+
function setup(){
28+
29+
// Note: You have to change the host var
30+
// if your client runs on a different machine than the websocket server
31+
32+
var host = "ws://music.james:6681/pusher";
33+
var socket = new WebSocket(host);
34+
var status = $('#status');
35+
var btnNotify = $("#notify");
36+
var name = $("#name");
37+
38+
// event handlers for UI
39+
btnNotify.on('click',function(){
40+
var object = {
41+
user: name.val(),
42+
count: 13,
43+
message: 'Tracks added'
44+
};
45+
console.log('sending message');
46+
console.log( object );
47+
socket.send( JSON.stringify(object) );
48+
});
49+
50+
// event handlers for websocket
51+
if(socket){
52+
53+
console.log(' socket valid ');
54+
55+
socket.onopen = function(){
56+
console.info("connection opened....");
57+
status.html( 'connected' );
58+
}
59+
60+
socket.onmessage = function( response ){
61+
console.info("Incoming...");
62+
console.log(response);
63+
showServerResponse( response.data );
64+
}
65+
66+
socket.onclose = function(){
67+
console.info("connection closed....");
68+
status.html( 'disconnected' );
69+
}
70+
71+
}else{
72+
console.log("invalid socket");
73+
}
74+
75+
function showServerResponse( response ){
76+
response = JSON.parse( response );
77+
var p = document.createElement('p');
78+
p.innerHTML = response.message + ' from '+ response.user;
79+
document.getElementById('output').appendChild(p);
80+
}
81+
82+
}
83+
84+
});
85+
86+
</script>
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import tornado.ioloop
2+
import tornado.web
3+
import tornado.websocket
4+
import tornado.template
5+
import logging
6+
import uuid
7+
import os
8+
import cgi
9+
from tornado.escape import json_encode,json_decode
10+
from mopidy import config, ext
11+
import subprocess
12+
13+
logger = logging.getLogger(__name__)
14+
clients = {}
15+
16+
## PUSHER WEBSOCKET SERVER
17+
class PusherHandler(tornado.websocket.WebSocketHandler):
18+
19+
def check_origin(self, origin):
20+
return True
21+
22+
def open(self):
23+
self.id = str(uuid.uuid4())
24+
self.details = {"id": self.id, "ip": self.request.remote_ip, "name": "User"}
25+
clients[self.id] = { 'details': self.details, 'connection': self}
26+
27+
# send a message to the client with it's assigned details
28+
connectedMessage = '{"pusher": "true", "startup": "true", "details": '+ json_encode(self.details) +'}'
29+
self.write_message( connectedMessage )
30+
logger.debug( 'New Spotmop Pusher connection: '+ self.id )
31+
32+
def on_message(self, message):
33+
for client in clients.itervalues():
34+
client['connection'].write_message(message)
35+
logger.debug( 'Spotmop Pusher message received from '+ self.id )
36+
37+
def on_close(self):
38+
if self.id in clients:
39+
del clients[self.id]
40+
logger.debug( 'Spotmop Pusher connection to '+ self.id +' closed' )
41+
42+
43+
## PUSHER HTTP ENDPOINT
44+
class PusherRequestHandler(tornado.web.RequestHandler):
45+
46+
def set_default_headers(self):
47+
self.set_header("Access-Control-Allow-Origin", "*")
48+
self.set_header("Access-Control-Allow-Methods", "GET,POST")
49+
self.set_header("Access-Control-Allow-Headers", "X-Requested-With")
50+
self.set_header("Content-Type", "application/json")
51+
52+
def initialize(self, core, config, version):
53+
self.core = core
54+
self.config = config
55+
self.version = version
56+
57+
# get method
58+
def get(self, action):
59+
60+
if action == 'me':
61+
id = self.get_query_argument('id')
62+
name = self.get_query_argument('name')
63+
64+
# save the payload name to the client list
65+
clients[id]['details']['name'] = name
66+
67+
# return the updated client details
68+
self.write( '{"status":"ok"}' )
69+
70+
elif action == 'connections':
71+
clientDetailsList = []
72+
for client in clients.itervalues():
73+
clientDetailsList.append(client['details'])
74+
self.write(json_encode(clientDetailsList))
75+
76+
def spotmop_pusher_factory(config, core):
77+
return [
78+
('/', PusherRequestHandler, {'core': core, 'config': config})
79+
]
80+
81+

0 commit comments

Comments
 (0)