Skip to content

Feature/websocket everywhere #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6d60cbe
Adds an cli interpreter for certified apps
316k Sep 22, 2014
93e9f42
Reorganize the js files
316k Sep 22, 2014
1d44966
Draft of a certified app manifest
316k Sep 22, 2014
bf0bccb
Adds fields for more server params + js reorder
316k Sep 22, 2014
5953394
Generic interface to send/receive data to a server
316k Sep 23, 2014
a6ed9eb
Uses Connection_HTTP() instead of direct HTTP GET
316k Sep 23, 2014
b6dd895
Cleans code and adapts to the new Connection style
316k Sep 23, 2014
796b05a
Cleans code
316k Sep 23, 2014
20b086e
Removes websocket test script
316k Sep 23, 2014
155247c
Adds a websocket driver for the server connection
316k Sep 23, 2014
83f7f58
Removes abusive debug code
316k Sep 23, 2014
6529715
Indicates the servers status on servers menu
316k Sep 23, 2014
48c3ffa
Moves configuration.js to to server root
316k Sep 23, 2014
1f68c13
Adds generic actions and connection drivers
316k Sep 25, 2014
2402605
Moves server js files from node_modules/ to lib/
316k Sep 25, 2014
4edf569
Corrections on the README.md
316k Sep 25, 2014
fc4ce99
Removes default ports in connection drivers
316k Sep 25, 2014
ccb9f2b
Groups clicks on tags with data-command attributes
316k Sep 25, 2014
97b1545
Connection between server and clients
316k Sep 26, 2014
b76b09a
Connection between server and clients
316k Sep 26, 2014
15e8642
Minor bugfixes
316k Sep 27, 2014
0d41ea9
Refresh delay in server configuration
316k Sep 27, 2014
8c1a391
Clears only the server name in #add-server
316k Sep 27, 2014
39c0e0f
Handles JSON errors in websocket driver
316k Sep 27, 2014
4d4cb3c
Updates sliders without looping
316k Sep 29, 2014
18c75ac
Merge branch 'feature/websocket-everywhere' of https://github.com/316…
316k Sep 29, 2014
ee79899
Merge branch 'master' of https://github.com/Agneli/linux-remote-contr…
316k Nov 5, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 16 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,36 +29,27 @@ Turn any device into a complete remote control for your GNU/Linux.

### Other systems

1 - Download this repository and unzip
In a command line :

```bash
# 1 - Download this repository and unzip
unzip linux-remote-control-master.zip
```

2 - Make a .deb package of the project
```bash
# 2 - Make a .deb package of the project
dpkg-deb -b linux-remote-control-master/ lrc.deb
```

3 - Install .deb package
```bash
# 3 - Install .deb package
sudo dpkg -i lrc.deb
```

4 - Move /opt/lrc-client directory to your device or to directory of your choice (if you prefer you can leave here)
```bash
# 4 - Move /opt/lrc-client directory to your device or to directory of your choice (if you prefer you can leave here)
sudo mv /opt/lrc-client your-directory/lrc-client
```

5 - Start lrc-server
```bash
node /opt/lrc-server/lrc.js
```
or
```bash
nodejs /opt/lrc-server/lrc.js
# 5 - Start lrc-server
# (depending on the OS, the server can be called `node` or `nodejs`)
node /opt/lrc-server/lrc.js || nodejs /opt/lrc-server/lrc.js
```

6 - Open the index.html of your-directory/lrc-client in a browser, add your server and have fun
Finally, open the index.html of your-directory/lrc-client in a browser, add your server and have fun !

## How to install lrc-server

Expand Down Expand Up @@ -89,7 +80,7 @@ Or open .deb package by graphic interface (double click on the lrc-ffos.deb file

### Configuration

Linux-remote-control will work out-of-the-box in most cases. However, if you wish to change the default settings (for instance, if you wish to use another music player than Rhythmbox), just modify the configuration file in /opt/lrc-server/node_modules/configuration.js
Linux-remote-control will work out-of-the-box in most cases. However, if you wish to change the default settings (for instance, if you wish to use another music player than Rhythmbox), just modify the configuration file in /opt/lrc-server/configuration.js

### Start the server on computer boot

Expand All @@ -103,7 +94,11 @@ $ crontab -e

### Firewall issues

The default ports for the server are 3000 for HTTP requests and 3001 for WebSockets. You might want to open those ports (at least when you are not on a public network) with tools such as `firewall-config`.
The default port the server is 3000. You might want to open that port (at least when you are not on a public network) with tools such as `firewall-config`, or using the following command :

```bash
sudo firewall-cmd --add-port=3000/tcp
```

## Dependences

Expand Down
113 changes: 73 additions & 40 deletions opt/lrc-client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
<div class="w20 right"></div>
</header>
<div class="line"></div>
<div class="line"></div>
<div class="line center">
<div class="fields">
<input type="text" name="name" id="name" data-i18n="[placeholder]lrc.add-server.account-name" />
Expand All @@ -43,8 +42,23 @@
<input type="text" name="ip" id="ip" data-i18n="[placeholder]lrc.add-server.ip-address" />
</div>
</div>
<div class="line"></div>
<div class="line"></div>
<div class="line center">
<small>Advanced configuration</small>
</div>
<div class="line center">
<div class="fields">
<select name="connection-type">
<option value="WebSocket">WebSocket</option>
<option value="HTTP">HTTP</option>
<!--option value="Bluetooth">TODO : Bluetooth</option-->
</select>
</div>
</div>
<div class="line center">
<div class="fields">
<input type="numeric" name="port" data-i18n="[placeholder]lrc.add-server.http-port" value="3000" />
</div>
</div>
<div class="line"></div>
<div class="line"></div>
<div class="line color2-light">
Expand Down Expand Up @@ -362,32 +376,34 @@
<a href="#!" class="w14 left" data-page="slideshow" data-direction='left'><i class="fa fa-unsorted fa-rotate-90"></i></a>
<a href="#!" class="w14 left" data-page="custom-commands" data-direction='left'><i class="fa fa-terminal"></i></a>
</header>
<div class="line center" data-watch="music.artist"></div>
<div class="line center" data-watch="music.album"></div>
<div class="line center" data-watch="music.title"></div>
<div class="line center"></div>
<div class="line"></div>
<div class="line center artist"></div>
<div class="line center album"></div>
<div class="line center title"></div>
<div class="line center paused"></div>
<div class="line color1-light center">
<a class="w20 left sound-min" data-command='{"step":"5"}'><i class="fa fa-volume-off"></i></a>
<a class="w20 right sound-max" data-command='{"step":"5"}'><i class="fa fa-volume-up"></i></a>
<a class="w20 left sound-min" data-step="5"><i class="fa fa-volume-off"></i></a>
<a class="w20 right sound-max" data-step="5"><i class="fa fa-volume-up"></i></a>
<div class="slider w60">
<span class="tooltip"></span>
<div class="sound-volume color1-dark" data-command='{"cmd":"amixer sset Master "}'></div>
<div class="sound-volume color1-dark" data-watch="volume" data-base-command='{"cmd":"amixer sset Master "}'></div>
<span class="volume"></span>
</div>
</div>
<div class="line color2-light center">
<div class="w20 left time elapsed">00:00</div>
<div class="w20 right time duration">00:00</div>
<div class="slider w60">
<span class="tooltip"></span>
<div class="timeline color2-dark" id="music-timeline" data-command='{"cmd":""}'></div>
<span class="volume"></span>
<div class="w20 left time" data-watch="music.elapsed-formatted">00:00</div>
<div class="w20 right time" data-watch="music.duration-formatted">00:00</div>
<div class="slider w60">
<span class="tooltip"></span>
<div class="timeline color2-dark" id="music-timeline" data-watch="music.elapsed-percent" data-command='{"cmd":""}'></div>
<span class="volume"></span>
</div>
</div>
<div class="line h20 color2-dark" id="music-controls">
<a href="#!" class="w25 left prev" data-action="previous"><i class="fa fa-fast-backward"></i></a>
<a href="#!" id="music-play-pause" class="w25 left play" data-action="toggle_play"><i class="fa fa-play"></i></a>
<a href="#!" class="w25 left play" data-action="toggle_play" data-watch="music.play_symbol">
<i class="fa fa-play"></i>
</a>
<a href="#!" class="w25 left next" data-action="next"><i class="fa fa-fast-forward"></i></a>
<a href="#!" class="w25 left stop" data-action="stop"><i class="fa fa-stop"></i></a>
<!--<a href="#!" class="w20 left mute" data-command='{"cmd":"export DISPLAY=:0; xdotool key XF86AudioMute"}'></a>-->
Expand All @@ -412,11 +428,11 @@
<div class="line"></div>
<div class="line"></div>
<div class="line color1-light center">
<a class="w20 left sound-min" data-command='{"step":"5"}'><i class="fa fa-volume-off"></i></a>
<a class="w20 right sound-max" data-command='{"step":"5"}'><i class="fa fa-volume-up"></i></a>
<a class="w20 left sound-min" data-step="5"><i class="fa fa-volume-off"></i></a>
<a class="w20 right sound-max" data-step="5"><i class="fa fa-volume-up"></i></a>
<div class="slider w60">
<span class="tooltip"></span>
<div class="sound-volume color1-dark" data-command='{"cmd":"amixer sset Master "}'></div>
<div class="sound-volume color1-dark" data-watch="volume" data-base-command='{"cmd":"amixer sset Master "}'></div>
<span class="volume"></span>
</div>
</div>
Expand Down Expand Up @@ -460,23 +476,39 @@
</div>
<div class="line"></div>
<div id="alt-tab" class="line h20 color1-light">
<a href="#!" class="w25 left alt-tab" data-command='{"cmd":"export DISPLAY=:0; xdotool keydown alt; sleep 0.5; xdotool key Tab"}'>Alt + tab</a>
<a href="#!" class="w25 left" data-command='{"cmd":"export DISPLAY=:0; xdotool keydown alt key Left"}'><i class="fa fa-2x fa-chevron-left"></i></a>
<a href="#!" class="w25 right ok" data-command='{"cmd":"export DISPLAY=:0; xdotool keyup alt keyup Tab keyup shift"}'><i class="fa fa-2x fa-check"></i></a>
<a href="#!" class="w25 right" data-command='{"cmd":"export DISPLAY=:0; xdotool keydown alt key Right"}'><i class="fa fa-2x fa-chevron-right"></i></a>
<a href="#!" class="w25 left alt-tab" data-command='{"cmd":"export DISPLAY=:0; xdotool keydown alt; sleep 0.5; xdotool key Tab"}'>
Alt + tab
</a>
<a href="#!" class="w25 left" data-command='{"cmd":"export DISPLAY=:0; xdotool keydown alt key Left"}'>
<i class="fa fa-2x fa-chevron-left"></i>
</a>
<a href="#!" class="w25 right ok" data-command='{"cmd":"export DISPLAY=:0; xdotool keyup alt keyup Tab keyup shift"}'>
<i class="fa fa-2x fa-check"></i>
</a>
<a href="#!" class="w25 right" data-command='{"cmd":"export DISPLAY=:0; xdotool keydown alt key Right"}'>
<i class="fa fa-2x fa-chevron-right"></i>
</a>
</div>
<div id="controls-controls" class="line h20 color2-light">
<a href="#!" class="w25 left lock" data-command='{"cmd":"export DISPLAY=:0; gnome-screensaver; gnome-screensaver-command -l"}'><i class="fa fa-2x fa-lock"></i></a>
<a href="#!" class="w25 left unlock" data-command='{"cmd":"export DISPLAY=:0; gnome-screensaver; gnome-screensaver-command -d"}'><i class="fa fa-2x fa-unlock"></i></a>
<a href="#!" id="reboot" class="w25 left reboot" data-command='{"cmd":"reboot"}'><i class="fa fa-2x fa-repeat"></i></a>
<a href="#!" id="shutdown" class="w25 left shutdown" data-command='{"cmd":"sudo halt"}'><i class="fa fa-2x fa-power-off"></i></a>
<a href="#!" class="w25 left lock" data-command='{"cmd":"export DISPLAY=:0; gnome-screensaver; gnome-screensaver-command -l"}'>
<i class="fa fa-2x fa-lock"></i>
</a>
<a href="#!" class="w25 left unlock" data-command='{"cmd":"export DISPLAY=:0; gnome-screensaver; gnome-screensaver-command -d"}'>
<i class="fa fa-2x fa-unlock"></i>
</a>
<a href="#!" id="reboot" class="w25 left reboot" data-confirm="Reboot" data-command='{"cmd":"reboot"}'>
<i class="fa fa-2x fa-repeat"></i>
</a>
<a href="#!" id="shutdown" class="w25 left shutdown" data-confirm="Shutdown" data-command='{"cmd":"sudo halt"}'>
<i class="fa fa-2x fa-power-off"></i>
</a>
</div>
<div class="line color2-dark center">
<a class="w20 left dark-screen" data-command='{"step":"10"}'><i class="fa fa-desktop"> -</i></a>
<a class="w20 right light-screen" data-command='{"step":"10"}'>+ <i class="fa fa-desktop"></i></a>
<a class="w20 left dark-screen" data-step="10"><i class="fa fa-desktop"> -</i></a>
<a class="w20 right light-screen" data-step="10">+ <i class="fa fa-desktop"></i></a>
<div class="slider w60">
<span class="tooltip"></span>
<div class="timeline color2-light" id="backlight" data-command='{"cmd":"xbacklight -set "}'></div>
<div class="timeline color2-light" id="backlight" data-watch="backlight" data-base-command='{"cmd":"xbacklight -set "}'></div>
<span class="volume"></span>
</div>
</div>
Expand Down Expand Up @@ -575,18 +607,19 @@
<a href="#!" class="w50 center right save" data-page="custom-commands" data-direction='down' data-i18n="lrc.add-server.save"></a>
</div>
</section>

</div>

<script type="text/javascript" src="js/jquery.js" ></script>
<script type="text/javascript" src="js/jquery-ui.js" ></script>
<script type="text/javascript" src="js/jquery-ui-touch-punch.js" ></script>
<script type="text/javascript" src="js/local-storage.js"></script>
<script type="text/javascript" src="js/lib/jquery.js" ></script>
<script type="text/javascript" src="js/lib/jquery-ui.js" ></script>
<script type="text/javascript" src="js/lib/jquery-ui-touch-punch.js" ></script>
<script type="text/javascript" src="js/lib/i18next.js" ></script>
<script type="text/javascript" src="js/lib/local-storage.js"></script>
<script type="text/javascript" src="js/custom-commands.js"></script>
<script type="text/javascript" src="js/servers.js"></script>
<script type="text/javascript" src="js/js.js" ></script>
<script type="text/javascript" src="js/touch.js" ></script>
<script type="text/javascript" src="js/i18next.js" ></script>

<script type="text/javascript" src="js/connection/connection.js"></script>
<script type="text/javascript" src="js/connection/http.js"></script>
<script type="text/javascript" src="js/connection/websocket.js"></script>
<script type="text/javascript" src="js/js.js"></script>
<script type="text/javascript" src="js/touch.js"></script>
</body>
</html>
Empty file.
17 changes: 17 additions & 0 deletions opt/lrc-client/js/connection/connection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
function Connection() {}

// Functions to implement with each driver
Connection.prototype.send = function(fct, arguments, callback) { throw new Error("Not implemented yet"); };
Connection.prototype.delete = function() { throw new Error("Not implemented yet"); };

/**
* Returns a new Connection_Driver based on the type of
* the server passed in parameter
*/
Connection.factory = function(server) {
var types = {
HTTP: Connection_HTTP,
WebSocket: Connection_WebSocket
};
return new types[server.type](server);
};
60 changes: 60 additions & 0 deletions opt/lrc-client/js/connection/http.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Driver to connect to a server via HTTP requests
* (slower and more memory-consuming than WebSocket)
*/
function Connection_HTTP(server) {
Connection.apply(this);

refresh_rate = server.refresh_rate || 1000;

this.url = "http://" + server.host + ":" + server.port + '/';

var that = this;
this.refresh_interval = setInterval(function() {
that.refresh();
}, refresh_rate);
}

// Extends Connection
Connection_HTTP.prototype = new Connection();

/**
* Sends a command to the server via HTTP GET
*/
Connection_HTTP.prototype.send = function(fct, arguments, callback) {
callback = callback || function() {};
arguments = arguments || {};

$.get(this.url + fct, arguments).done(callback);
};

Connection_HTTP.prototype.delete = function() {
clearInterval(this.refresh_interval);
};

/**
* Called every `refresh_rate` miliseconds to fetch useful data from the server,
* including volume, backlight and music infos.
*/
Connection_HTTP.prototype.refresh = function() {
var requests = ['info', 'music_info'];
for(var index in requests) {
// Callback function refreshes every HTML tag that
// has a [data-watch] that is a key in data.
$.get(this.url + requests[index]).done(function(data) {
for(object in data) {
if(data[object] instanceof Object) {
for(key in data[object]) {
var watch_selector = '[data-watch="' + object + '.' + key + '"]';
$(watch_selector + ':not(.slider ' + watch_selector + ')').html(unescape(data[object][key]));
$('.slider ' + watch_selector).slider("value", unescape(data[object][key]));
}
} else {
var watch_selector = '[data-watch="' + object + '"]';
$(watch_selector + ':not(.slider ' + watch_selector + ')').html(unescape(data[object]));
$('.slider ' + watch_selector).slider("value", unescape(data[object]));
}
}
});
}
};
71 changes: 71 additions & 0 deletions opt/lrc-client/js/connection/websocket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Driver to connect to a server via a WebSocket
*/
function Connection_WebSocket(server) {
Connection.apply(this);

window.WebSocket = window.WebSocket || window.MozWebSocket;
this.websocket = new WebSocket("ws://" + server.host + ":" + server.port + '/');

// Log about the WebSocket connection
this.websocket.onopen = function () { console.log('WebSocket connection opened'); };
this.websocket.onclose = function () {
console.log('WebSocket connection closed');
if(confirm('Connection to the server lost ! Reload app ?')) {
window.location.reload();
}
};
this.websocket.onerror = function (error) { console.error('WebSocket error : ' + error); };

var that = this;
this.websocket.onmessage = function (message) {
that.refresh(message.data);
};
}

// Extends Connection
Connection_WebSocket.prototype = new Connection();

Connection_WebSocket.prototype.delete = function() {
this.websocket.onclose = null;
this.websocket.close();
};

/**
* Sends a command to the server via HTTP GET
*/
Connection_WebSocket.prototype.send = function(fct, arguments, callback) {
this.websocket.send(fct + '/' + JSON.stringify(arguments));
// TODO : Deal with the callback
};

/**
* Callback used to refresh the view when a WebSocket message is received
*/
Connection_WebSocket.prototype.refresh = function(data) {
if(!data) {
return;
}

try {
data = $.parseJSON(data);
} catch(json_error) {
// Ignore parse errors
console.error(json_error);
return
}

for(object in data) {
if(data[object] instanceof Object) {
for(key in data[object]) {
var watch_selector = '[data-watch="' + object + '.' + key + '"]';
$(watch_selector + ':not(.slider ' + watch_selector + ')').html(unescape(data[object][key]));
$('.slider ' + watch_selector).slider("value", unescape(data[object][key]));
}
} else {
var watch_selector = '[data-watch="' + object + '"]';
$(watch_selector + ':not(.slider ' + watch_selector + ')').html(unescape(data[object]));
$('.slider ' + watch_selector).slider("value", unescape(data[object]));
}
}
};
Loading