diff --git a/config/nodejs.config.yml b/config/nodejs.config.yml
new file mode 100644
index 0000000..9abe473
--- /dev/null
+++ b/config/nodejs.config.yml
@@ -0,0 +1,4 @@
+nodejs_server_scheme: http
+nodejs_server_host: localhost
+nodejs_server_port: 8080
+nodejs_pages: *
diff --git a/config/schema/nodejs.schema.yml b/config/schema/nodejs.schema.yml
new file mode 100644
index 0000000..c637d43
--- /dev/null
+++ b/config/schema/nodejs.schema.yml
@@ -0,0 +1,17 @@
+# Schema for the configuration files of the nodejs module.
+nodejs.config:
+  type: mapping
+  label: 'Nodejs config'
+  mapping:
+    nodejs_server_scheme:
+      type: string
+      label: 'Protocol used by Node.js server'
+    nodejs_server_host:
+      type: string
+      label: 'Node.js server host'
+    nodejs_server_port:
+      type: string
+      label: 'Node.js server port'
+    nodejs_pages:
+      type: string
+      label: 'Pages on which to enable nodejs'
diff --git a/lib/Drupal/nodejs/EventSubscriber/NodejsSubscriber.php b/lib/Drupal/nodejs/EventSubscriber/NodejsSubscriber.php
new file mode 100644
index 0000000..5608aaa
--- /dev/null
+++ b/lib/Drupal/nodejs/EventSubscriber/NodejsSubscriber.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\nodejs\EventSubscriber\NodejsSubscriber.
+ */
+
+namespace Drupal\nodejs\EventSubscriber;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+class NodejsSubscriber implements EventSubscriberInterface {
+
+  public function initLibraries(GetResponseEvent $event) {
+    drupal_register_shutdown_function(array('Nodejs', 'sendMessages'));
+    if (nodejs_add_js_to_page_check()) {
+      drupal_add_library('nodejs', 'init');
+    }
+    
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('initLibraries', 40);
+    return $events;
+  }
+
+}
diff --git a/lib/Drupal/nodejs/Form/AddUserToChannelForm.php b/lib/Drupal/nodejs/Form/AddUserToChannelForm.php
new file mode 100644
index 0000000..e91d3b4
--- /dev/null
+++ b/lib/Drupal/nodejs/Form/AddUserToChannelForm.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Form\AddUserToChannelForm.
+ */
+
+namespace Drupal\nodejs\Form;
+
+
+use Drupal\Core\Form\FormBase;
+
+/**
+ * {@inheritdoc}
+ */
+class AddUserToChannelForm extends FormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormID() {
+    return 'nodejs_add_user_to_channel_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, array &$form_state) {
+    $form = array();
+    $form['nodejs_uid'] = array(
+      '#type' => 'textfield',
+      '#description' => t('The user uid to add to a channel.'),
+      '#title' => t('User uid to add'),
+    );
+    $form['nodejs_channel'] = array(
+      '#type' => 'textfield',
+      '#description' => t('The name of the channel to give a user access to.'),
+      '#title' => t('Channel to add'),
+    );
+    $form['nodejs_submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Add user'),
+    );
+    return $form;
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, array &$form_state) {
+    $values = (object) $form_state['values'];
+    if (!preg_match('/^\d+$/', $values->nodejs_uid)) {
+      form_set_error('nodejs_uid', t('Invalid uid - please enter a numeric uid.'));
+    }
+    if (!preg_match('/^([a-z0-9_]+)$/i', $values->nodejs_channel)) {
+      form_set_error('nodejs_channel', t('Invalid channel name - only numbers, letters and underscores are allowed.'));
+    }
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    $values = (object) $form_state['values'];
+    if (nodejs_add_user_to_channel($values->nodejs_uid, $values->nodejs_channel)) {
+      drupal_set_message(t("Added uid %uid to %channel.", array('%uid' => $values->nodejs_uid, '%channel' => $values->nodejs_channel)));
+    }
+    else {
+      drupal_set_message(t("Failed to add uid %uid to %channel.", array('%uid' => $$values->nodejs_uid, '%channel' => $values->nodejs_channel)), 'error');
+    }
+  }
+
+}
diff --git a/lib/Drupal/nodejs/Form/NodejsConfigForm.php b/lib/Drupal/nodejs/Form/NodejsConfigForm.php
new file mode 100644
index 0000000..1005e25
--- /dev/null
+++ b/lib/Drupal/nodejs/Form/NodejsConfigForm.php
@@ -0,0 +1,98 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Form\NodejsConfigForm.
+ */
+
+namespace Drupal\nodejs\Form;
+
+use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\Config\Context\ContextInterface;
+use Drupal\Core\Form\ConfigFormBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Configure node.js integration.
+ */
+class NodejsConfigForm extends ConfigFormBase {
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('config.factory'),
+      $container->get('config.context.free')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormID() {
+    return 'nodejs_settings';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, array &$form_state) {
+    $config = $this->configFactory->get('nodejs.config');
+    $form['server'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Node.js server'),
+    );
+    $form['server']['nodejs_server_scheme'] = array(
+      '#type' => 'radios',
+      '#title' => t('Protocol used by Node.js server'),
+      '#default_value' => $config->get('nodejs_server_scheme'),
+      '#options' => array('http' => t('http'), 'https' => t('https')),
+      '#description' => t('The protocol used to communicate with the Node.js server.'),
+    );
+    $form['server']['nodejs_server_host'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Node.js server host'),
+      '#default_value' => $config->get('nodejs_server_host'),
+      '#size' => 40,
+      '#required' => TRUE,
+      '#description' => t('The hostname of the Node.js server.'),
+    );
+    $form['server']['nodejs_server_port'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Node.js server port'),
+      '#default_value' => $config->get('nodejs_server_port'),
+      '#size' => 10,
+      '#required' => TRUE,
+      '#description' => t('The port of the Node.js server.'),
+    );
+    $description = t("Enter one page per line as Drupal paths. The '*' character is a wildcard.
+                      Example paths are %blog for the blog page and %blog-wildcard for every personal blog.
+                      %front is the front page.",
+                      array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>'));
+    $form['server']['nodejs_pages'] = array(
+      '#type' => 'textarea',
+      '#title' => t('Pages on which to enable nodejs'),
+      '#default_value' => $config->get('nodejs_pages'),
+      '#required' => TRUE,
+      '#description' => $description,
+    );
+
+    return parent::buildForm($form, $form_state);
+  }
+  
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    $this->configFactory->get('nodejs.config')
+      ->set('nodejs_server_scheme', $form_state['values']['nodejs_server_scheme'])
+      ->set('nodejs_server_host', $form_state['values']['nodejs_server_host'])
+      ->set('nodejs_server_port', $form_state['values']['nodejs_server_port'])
+      ->set('nodejs_pages', $form_state['values']['nodejs_pages'])
+      ->save();
+
+    parent::submitForm($form, $form_state);
+  }
+}
diff --git a/lib/Drupal/nodejs/NodejsPages.php b/lib/Drupal/nodejs/NodejsPages.php
new file mode 100644
index 0000000..86da05c
--- /dev/null
+++ b/lib/Drupal/nodejs/NodejsPages.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\nodejs\Controller\SystemController.
+ */
+
+namespace Drupal\nodejs;
+
+use Symfony\Component\HttpFoundation\JsonResponse;
+
+/**
+ * Returns responses for Node.js routes.
+ */
+class NodejsPages{
+  
+
+  /**
+   * @todo .
+   */
+  public function messageHandler() {
+    if (!isset($_POST['serviceKey']) || !nodejs_is_valid_service_key($_POST['serviceKey'])) {
+      return new JsonResponse(array('error' => 'Invalid service key.'));
+    }
+  
+    if (!isset($_POST['messageJson'])) {
+      return new JsonResponse(array('error' => 'No message.'));
+    }
+  
+    $message = drupal_json_decode($_POST['messageJson']);
+    $response = array();
+    switch ($message['messageType']) {
+      case 'authenticate':
+        $response = nodejs_auth_check($message);
+        break;
+  
+      case 'userOffline':
+        nodejs_user_set_offline($message['uid']);
+        break;
+  
+      default:
+        $handlers = array();
+        foreach (module_implements('nodejs_message_callback') as $module) {
+          $function = $module . '_nodejs_message_callback';
+          $handlers += $function($message['messageType']);
+        }
+        foreach ($handlers as $callback) {
+          $callback($message, $response);
+        }
+    }
+    drupal_alter('nodejs_message_response', $response, $message);
+  
+    return new JsonResponse($response ? $response : array('error' => 'Not implemented'));
+  }
+
+}
diff --git a/nodejs.admin.inc b/nodejs.admin.inc
deleted file mode 100644
index 9585f6e..0000000
--- a/nodejs.admin.inc
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-/**
- * @file
- * Admin page callbacks for the Node.js module.
- */
-
-/**
- * Form builder function for module settings.
- */
-function nodejs_settings() {
-  $form['server'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Node.js server'),
-  );
-  $form['server']['nodejs_server_scheme'] = array(
-    '#type' => 'radios',
-    '#title' => t('Protocol used by Node.js server'),
-    '#default_value' => variable_get('nodejs_server_scheme', 'http'),
-    '#options' => array('http' => t('http'), 'https' => t('https')),
-    '#description' => t('The protocol used to communicate with the Node.js server.'),
-  );
-  $form['server']['nodejs_server_host'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Node.js server host'),
-    '#default_value' => variable_get('nodejs_server_host', 'localhost'),
-    '#size' => 40,
-    '#required' => TRUE,
-    '#description' => t('The hostname of the Node.js server.'),
-  );
-  $form['server']['nodejs_server_port'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Node.js server port'),
-    '#default_value' => variable_get('nodejs_server_port', '8080'),
-    '#size' => 10,
-    '#required' => TRUE,
-    '#description' => t('The port of the Node.js server.'),
-  );
-  $description = t("Enter one page per line as Drupal paths. The '*' character is a wildcard.
-                    Example paths are %blog for the blog page and %blog-wildcard for every personal blog.
-                    %front is the front page.",
-                    array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>'));
-  $form['server']['nodejs_pages'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Pages on which to enable nodejs'),
-    '#default_value' => variable_get('nodejs_pages', '*'),
-    '#required' => TRUE,
-    '#description' => $description,
-  );
-
-  return system_settings_form($form);
-}
-
diff --git a/nodejs.info b/nodejs.info
deleted file mode 100644
index 553a2c1..0000000
--- a/nodejs.info
+++ /dev/null
@@ -1,7 +0,0 @@
-name = Nodejs integration
-description = Adds Node.js support to Drupal
-package = Nodejs
-version = VERSION
-core = 7.x
-files[] = nodejs.module
-configure = admin/config/nodejs
diff --git a/nodejs.info.yml b/nodejs.info.yml
new file mode 100644
index 0000000..34cf8fa
--- /dev/null
+++ b/nodejs.info.yml
@@ -0,0 +1,7 @@
+name: Nodejs integration
+type: module
+description: 'Adds Node.js support to Drupal.'
+package: Nodejs
+version: VERSION
+core: 8.x
+configure: nodejs.settings
diff --git a/nodejs.install b/nodejs.install
index d00eef3..88ef3a1 100644
--- a/nodejs.install
+++ b/nodejs.install
@@ -5,14 +5,6 @@
  * Install, update and uninstall functions for the nodejs module.
  */
 
-/**
- * Implements hook_uninstall().
- */
-function nodejs_uninstall() {
-  variable_del('nodejs_server_scheme');
-  variable_del('nodejs_server_host');
-  variable_del('nodejs_server_port');
-}
 
 /**
  * Implements hook_schema().
diff --git a/nodejs.js b/nodejs.js
index d464e03..657a351 100644
--- a/nodejs.js
+++ b/nodejs.js
@@ -1,5 +1,5 @@
 
-(function ($) {
+(function ($, Drupal, drupalSettings) {
 
 Drupal.Nodejs = Drupal.Nodejs || {
   'contentChannelNotificationCallbacks': {},
@@ -10,7 +10,7 @@ Drupal.Nodejs = Drupal.Nodejs || {
 };
 
 Drupal.behaviors.nodejs = {
-  attach: function (context, settings) {
+  attach: function () {
     if (!Drupal.Nodejs.socket) {
       Drupal.Nodejs.connect();
     }
@@ -81,13 +81,13 @@ Drupal.Nodejs.runSetupHandlers = function (type) {
 };
 
 Drupal.Nodejs.connect = function () {
-  var scheme = Drupal.settings.nodejs.client.secure ? 'https' : 'http',
-      url = scheme + '://' + Drupal.settings.nodejs.client.host + ':' + Drupal.settings.nodejs.client.port;
-  Drupal.settings.nodejs.connectTimeout = Drupal.settings.nodejs.connectTimeout || 5000;
+  var scheme = drupalSettings.nodejs.client.secure ? 'https' : 'http',
+      url = scheme + '://' + drupalSettings.nodejs.client.host + ':' + drupalSettings.nodejs.client.port;
+  drupalSettings.nodejs.connectTimeout = drupalSettings.nodejs.connectTimeout || 5000;
   if (typeof io === 'undefined') {
      return false;
   }
-  Drupal.Nodejs.socket = io.connect(url, {'connect timeout': Drupal.settings.nodejs.connectTimeout});
+  Drupal.Nodejs.socket = io.connect(url, {'connect timeout': drupalSettings.nodejs.connectTimeout});
   Drupal.Nodejs.socket.on('connect', function() {
     Drupal.Nodejs.sendAuthMessage();
     Drupal.Nodejs.runSetupHandlers('connect');
@@ -112,7 +112,7 @@ Drupal.Nodejs.connect = function () {
       Drupal.ajax.prototype.beforeSerialize = Drupal.Nodejs.originalBeforeSerialize;
     }
   });
-  setTimeout("Drupal.Nodejs.checkConnection()", Drupal.settings.nodejs.connectTimeout + 250);
+  setTimeout("Drupal.Nodejs.checkConnection()", drupalSettings.nodejs.connectTimeout + 250);
 };
 
 Drupal.Nodejs.checkConnection = function () {
@@ -123,13 +123,13 @@ Drupal.Nodejs.checkConnection = function () {
 
 Drupal.Nodejs.sendAuthMessage = function () {
   var authMessage = {
-    authToken: Drupal.settings.nodejs.authToken,
-    contentTokens: Drupal.settings.nodejs.contentTokens
+    authToken: drupalSettings.nodejs.authToken,
+    contentTokens: drupalSettings.nodejs.contentTokens
   };
   Drupal.Nodejs.socket.emit('authenticate', authMessage);
 };
 
-})(jQuery);
+})(jQuery, Drupal, drupalSettings);
 
 // vi:ai:expandtab:sw=2 ts=2
 
diff --git a/nodejs.module b/nodejs.module
index 830a190..7d88297 100644
--- a/nodejs.module
+++ b/nodejs.module
@@ -1,10 +1,14 @@
 <?php
 
+use Drupal\Component\Utility\Crypt;
+use Guzzle\Http\Exception\BadResponseException;
+use Guzzle\Http\Exception\RequestException;
+
 /**
  * Generate a token for a piece of content.
  */
 function nodejs_generate_content_token() {
-  return drupal_hmac_base64(drupal_random_bytes(512), drupal_get_private_key() . drupal_get_hash_salt());
+  return Crypt::hmacBase64(uniqid(mt_rand(), TRUE), \Drupal::service('private_key')->get() . drupal_get_hash_salt());
 }
 
 /**
@@ -234,26 +238,6 @@ function nodejs_send_role_message($role_name, $subject, $body) {
 }
 
 /**
- * Implements hook_init().
- */
-function nodejs_init() {
-  drupal_register_shutdown_function(array('Nodejs', 'sendMessages'));
-  if (nodejs_add_js_to_page_check()) {
-    $_SESSION['nodejs_config'] = $nodejs_config = nodejs_get_config();
-    if (isset($nodejs_config['serviceKey'])) {
-      unset($nodejs_config['serviceKey']);
-    }
-    $socket_io_config = nodejs_get_socketio_js_config($nodejs_config);
-    drupal_add_js($socket_io_config['path'], array('type' => $socket_io_config['type']));
-    drupal_add_js(drupal_get_path('module', 'nodejs') . '/nodejs.js', array('type' => 'file'));
-    drupal_add_js(array('nodejs' => $nodejs_config), array('type' => 'setting'));
-    foreach (nodejs_get_js_handlers() as $handler_file) {
-      drupal_add_js($handler_file, array('type' => 'file'));
-    }
-  }
-}
-
-/**
  * Check if we should add the node.js js to the page.
  *
  * We check the url, and whether or not the admin has closed down access to
@@ -261,9 +245,10 @@ function nodejs_init() {
  */
 function nodejs_add_js_to_page_check() {
   global $user;
-
-  $valid_page = drupal_match_path(drupal_get_path_alias(), variable_get('nodejs_pages', '*'));
-  if (variable_get('nodejs_authenticated_users_only', FALSE)) {
+  $path = \Drupal::service('path.alias_manager')->getPathAlias(current_path());
+  $cinfig_paths = \Drupal::config('nodejs.config')->get('nodejs_pages');
+  $valid_page = drupal_match_path($path, $cinfig_paths);
+  if (\Drupal::config('nodejs.config')->get('nodejs_authenticated_users_only')) {
     $valid_user = $user->uid > 0;
   }
   else {
@@ -277,8 +262,8 @@ function nodejs_add_js_to_page_check() {
  */
 function nodejs_get_socketio_js_config($nodejs_config) {
   $socket_io_config = array(
-    'path' => variable_get('nodejs_socket_io_path', FALSE),
-    'type' => variable_get('nodejs_socket_io_type', 'external'),
+    'path' => \Drupal::config('nodejs.config')->get('nodejs_socket_io_path'),
+    'type' => \Drupal::config('nodejs.config')->get('nodejs_socket_io_type') ?: 'external',
   );
   if (!$socket_io_config['path']) {
     $socket_io_config['path'] = $nodejs_config['client']['scheme'] . '://' . $nodejs_config['client']['host'] . ':'
@@ -306,33 +291,49 @@ function nodejs_menu() {
       'description' => 'Configure nodejs module.',
       'position' => 'left',
       'weight' => -20,
-      'page callback' => 'system_admin_menu_block_page',
-      'access arguments' => array('access administration pages'),
-      'file' => 'system.admin.inc',
-      'file path' => drupal_get_path('module', 'system'),
+      'position' => 'right',
+      'route_name' => 'nodejs.settings',
     ),
     'admin/config/nodejs/config' => array(
       'title' => 'Configuration',
       'description' => 'Adjust node.js settings.',
-      'page callback' => 'drupal_get_form',
-      'page arguments' => array('nodejs_settings'),
-      'access arguments' => array('administer site configuration'),
-      'file' => 'nodejs.admin.inc',
-    ),
-    'nodejs/message' => array(
-      'title' => 'Message from Node.js server',
-      'page callback' => 'nodejs_message_handler',
-      'access callback' => TRUE,
-      'type' => MENU_CALLBACK,
+      'route_name' => 'nodejs.settings_config',
     ),
-    'nodejs/user/channel/add' => array(
-      'title' => 'Add a channel to the Node.js server',
-      'page callback' => 'drupal_get_form',
-      'page arguments' => array('nodejs_add_user_to_channel_form'),
-      'access callback' => TRUE,
-      'type' => MENU_CALLBACK,
+  );
+}
+
+/**
+ * Implements hook_library_info().
+ */
+function nodejs_library_info() {
+  $_SESSION['nodejs_config'] = $nodejs_config = nodejs_get_config();
+  if (isset($nodejs_config['serviceKey'])) {
+    unset($nodejs_config['serviceKey']);
+  }
+  $socket_io_config = nodejs_get_socketio_js_config($nodejs_config);
+
+  $libraries['init'] = array(
+    'title' => 'Init nodejs',
+    'website' => 'https://drupal.org/project/nodejs',
+    'version' => '1.1',
+    'js' => array(
+      $socket_io_config['path'] => array(
+        'type' => $socket_io_config['type'],
+      ),
+      drupal_get_path('module', 'nodejs') . '/nodejs.js' => array(
+        'type' => 'file',
+      ),
+      array(
+        'type' => 'setting',
+        'data' => array('nodejs' => $nodejs_config),
+      ),
     ),
   );
+  
+  foreach (nodejs_get_js_handlers() as $handler_file) {
+    $libraries['init']['js'][$handler_file] = array('type' => 'file');
+  }
+  return $libraries;
 }
 
 /**
@@ -406,65 +407,6 @@ function nodejs_get_remove_channel($channel) {
 }
 
 /**
- * Form callback, add a user to a channel.
- *
- * @param mixed $form
- * @param mixed $form_state
- * @return array
- */
-function nodejs_add_user_to_channel_form($form, $form_state) {
-  $form = array();
-  $form['nodejs_uid'] = array(
-    '#type' => 'textfield',
-    '#description' => t('The user uid to add to a channel.'),
-    '#title' => t('User uid to add'),
-  );
-  $form['nodejs_channel'] = array(
-    '#type' => 'textfield',
-    '#description' => t('The name of the channel to give a user access to.'),
-    '#title' => t('Channel to add'),
-  );
-  $form['nodejs_submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Add user'),
-  );
-  return $form;
-}
-
-/**
- * Form submit callback - add a user to a channel on the Node.js server.
- *
- * @param mixed $form
- * @param mixed $form_state
- */
-function nodejs_add_user_to_channel_form_submit($form, &$form_state) {
-  $values = (object) $form_state['values'];
-  if (nodejs_add_user_to_channel($values->nodejs_uid, $values->nodejs_channel)) {
-    drupal_set_message(t("Added uid %uid to %channel.", array('%uid' => $values->nodejs_uid, '%channel' => $values->nodejs_channel)));
-  }
-  else {
-    drupal_set_message(t("Failed to add uid %uid to %channel.", array('%uid' => $$values->nodejs_uid, '%channel' => $values->nodejs_channel)), 'error');
-  }
-}
-
-/**
- * Form validate callback - add a user to a channel on the Node.js server.
- *
- * @param mixed $form
- * @param mixed $form_state
- * @return void
- */
-function nodejs_add_user_to_channel_form_validate($form, &$form_state) {
-  $values = (object) $form_state['values'];
-  if (!preg_match('/^\d+$/', $values->nodejs_uid)) {
-    form_set_error('nodejs_uid', t('Invalid uid - please enter a numeric uid.'));
-  }
-  if (!preg_match('/^([a-z0-9_]+)$/i', $values->nodejs_channel)) {
-    form_set_error('nodejs_channel', t('Invalid channel name - only numbers, letters and underscores are allowed.'));
-  }
-}
-
-/**
  * Enqueue a message for sending at the end of the request.
  *
  * @param StdClass $message
@@ -488,7 +430,7 @@ function nodejs_send_message(StdClass $message) {
  * Implements hook_nodejs_user_channels().
  */
 function nodejs_nodejs_user_channels($account) {
-  if (variable_get('nodejs_enable_userchannel', TRUE) && $account->uid) {
+  if (\Drupal::config('nodejs.config')->get('nodejs_enable_userchannel') && $account->uid) {
     return array('nodejs_user_' . $account->uid);
   }
   return array();
@@ -505,55 +447,16 @@ function nodejs_user_logout($account) {
  * Check if the given service key is valid.
  */
 function nodejs_is_valid_service_key($service_key) {
-  return $service_key == variable_get('nodejs_service_key', '');
+  return $service_key == \Drupal::config('nodejs.config')->get('nodejs_service_key');
 }
 
-/**
- * Menu callback: handles all messages from Node.js server.
- */
-function nodejs_message_handler() {
-  if (!isset($_POST['serviceKey']) || !nodejs_is_valid_service_key($_POST['serviceKey'])) {
-    drupal_json_output(array('error' => 'Invalid service key.'));
-    drupal_exit();
-  }
 
-  if (!isset($_POST['messageJson'])) {
-    drupal_json_output(array('error' => 'No message.'));
-    drupal_exit();
-  }
-
-  $message = drupal_json_decode($_POST['messageJson']);
-  $response = array();
-  switch ($message['messageType']) {
-    case 'authenticate':
-      $response = nodejs_auth_check($message);
-      break;
-
-    case 'userOffline':
-      nodejs_user_set_offline($message['uid']);
-      break;
-
-    default:
-      $handlers = array();
-      foreach (module_implements('nodejs_message_callback') as $module) {
-        $function = $module . '_nodejs_message_callback';
-        $handlers += $function($message['messageType']);
-      }
-      foreach ($handlers as $callback) {
-        $callback($message, $response);
-      }
-  }
-  drupal_alter('nodejs_message_response', $response, $message);
-
-  drupal_json_output($response ? $response : array('error' => 'Not implemented'));
-  drupal_exit();
-}
 
 /**
  * Checks the given key to see if it matches a valid session.
  */
 function nodejs_auth_check($message) {
-  $nodejs_auth_check_callback = variable_get('nodejs_auth_check_callback', 'nodejs_auth_check_callback');
+  $nodejs_auth_check_callback = \Drupal::config('nodejs.config')->get('nodejs_auth_check_callback') ?: 'nodejs_auth_check_callback';
   if (!function_exists($nodejs_auth_check_callback)) {
     throw new Exception("No nodejs_auth_check callback found - looked for '$nodejs_auth_check_callback'.");
   }
@@ -599,7 +502,7 @@ function nodejs_auth_check_callback($auth_token) {
  * Get an auth token for the current user.
  */
 function nodejs_auth_get_token($account) {
-  $nodejs_auth_get_token_callback = variable_get('nodejs_auth_get_token_callback', 'nodejs_auth_get_token_callback');
+  $nodejs_auth_get_token_callback = \Drupal::config('nodejs.config')->get('nodejs_auth_get_token_callback') ?: 'nodejs_auth_get_token_callback';
   if (!function_exists($nodejs_auth_get_token_callback)) {
     throw new Exception("Cannot proceed without a valid nodejs_auth_get_token callback - looked for '$nodejs_auth_get_token_callback'.");
   }
@@ -645,27 +548,27 @@ function nodejs_user_set_offline($uid) {
  */
 function nodejs_get_config() {
   global $user;
-
+ $config = \Drupal::config('nodejs.config');
   $defaults = array(
     'nodejs' => array(
-      'scheme' => variable_get('nodejs_server_scheme', 'http'),
-      'secure' => variable_get('nodejs_server_scheme', 'http') == 'https' ? 1 : 0,
-      'host' => variable_get('nodejs_server_host', 'localhost'),
-      'port' => variable_get('nodejs_server_port', '8080'),
+      'scheme' => $config->get('nodejs_server_scheme') ?: 'http',
+      'secure' => $config->get('nodejs_server_scheme') == 'https' ? 1 : 0,
+      'host' => $config->get('nodejs_server_host') ?: 'localhost',
+      'port' => $config->get('nodejs_server_port') ?: 8080,
     ),
     'client' => array(
-      'scheme' => variable_get('nodejs_client_js_scheme', variable_get('nodejs_server_scheme', 'http')),
-      'secure' => variable_get('nodejs_client_js_scheme', variable_get('nodejs_server_scheme', 'http')) == 'https' ? 1 : 0,
-      'host' => variable_get('nodejs_client_js_host', variable_get('nodejs_server_host', 'localhost')),
-      'port' => variable_get('nodejs_client_js_port', variable_get('nodejs_server_port', '8080')),
+      'scheme' => $config->get('nodejs_client_js_scheme') ?: $config->get('nodejs_server_scheme'),
+      'secure' => $config->get('nodejs_client_js_scheme') ?: $config->get('nodejs_server_scheme') == 'https' ? 1 : 0,
+      'host' => $config->get('nodejs_client_js_host') ?: $config->get('nodejs_server_host'),
+      'port' => $config->get('nodejs_client_js_port') ?: $config->get('nodejs_server_port'),
     ),
-    'resource' => variable_get('nodejs_config_resource', '/socket.io'),
+    'resource' => $config->get('nodejs_config_resource') ?: '/socket.io',
     'authToken' => nodejs_auth_get_token($user),
-    'serviceKey' => variable_get('nodejs_service_key', ''),
+    'serviceKey' => $config->get('nodejs_service_key') ?: '',
     'websocketSwfLocation' => base_path() . drupal_get_path('module', 'nodejs') . '/socket_io/socket.io/support/socket.io-client/lib/vendor/web-socket-js/WebSocketMain.swf',
-    'log_http_errors' => variable_get('nodejs_log_http_errors', TRUE),
+    'log_http_errors' => $config->get('nodejs_log_http_errors') ?: TRUE,
   );
-  return variable_get('nodejs_config', array()) + $defaults;
+  return $config->get('nodejs_config') ?: array() + $defaults;
 }
 
 /**
@@ -867,26 +770,28 @@ class Nodejs {
 
   public static function httpRequest($url, $options) {
     self::initConfig();
-    $response = drupal_http_request(self::$baseUrl . $url, $options);
-    // If a http error occurred, and logging of http errors is enabled, log it.
-    if (isset($response->error)) {
-      if (self::$config['log_http_errors']) {
-        $params = array(
-          '%code' => $response->code,
-          '%error' => $response->error,
-          '%url' => $url,
-        );
-        $log_message = 'Error reaching the Node.js server at "%url": [%code] %error.';
-        if (!empty($options['data'])) {
-          $params['data'] = $options['data'];
-          $log_message = 'Error reaching the Node.js server at "%url" with data "%data": [%code] %error.';
-        }
-        watchdog('nodejs', t($log_message, $params));
+    $request = \Drupal::service('http_default_client')
+      ->get(self::$baseUrl . $url, null,$options);
+    try {
+      $response = $request->send();
+    
+    
+    
+      if ($response->getStatusCode() != 200) {
+        return FALSE;
       }
+    
+      return json_decode($response->getBody(TRUE));
+    }
+    catch (BadResponseException $e) {
+      watchdog('nodejs', 'Error reaching the Node.js server');
       return FALSE;
     }
-    // No errors, so return Node.js server response.
-    return json_decode($response->data);
+    catch (RequestException $e) {
+      watchdog('nodejs', 'Error reaching the Node.js server');
+      return FALSE;
+    }
+    return FALSE;
   }
 }
 
diff --git a/nodejs.routing.yml b/nodejs.routing.yml
new file mode 100644
index 0000000..dbce127
--- /dev/null
+++ b/nodejs.routing.yml
@@ -0,0 +1,29 @@
+nodejs.settings:
+  path: '/admin/config/nodejs'
+  defaults:
+    _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage'
+    _title: 'Nodejs'
+  requirements:
+    _permission: 'access administration pages'
+
+nodejs.settings_config:
+  path: '/admin/config/nodejs/config'
+  defaults:
+    _form: 'Drupal\nodejs\Form\NodejsConfigForm'
+  requirements:
+    _permission: 'administer site configuration'
+
+nodejs.message:
+  path: '/nodejs/message'
+  defaults:
+    _title: 'Message from Node.js server'
+    _content: '\Drupal\nodejs\NodejsPages::messageHandler'
+  requirements:
+    _access: 'TRUE'
+
+nodejs.add_channel:
+  path: '/nodejs/user/channel/add'
+  defaults:
+    _form: 'Drupal\nodejs\Form\AddUserToChannelForm'
+  requirements:
+    _access: 'TRUE'
diff --git a/nodejs.services.yml b/nodejs.services.yml
new file mode 100644
index 0000000..c8c6a18
--- /dev/null
+++ b/nodejs.services.yml
@@ -0,0 +1,5 @@
+services:
+  nodejs.subscriber:
+    class: Drupal\nodejs\EventSubscriber\NodejsSubscriber
+    tags:
+      - {name: event_subscriber}
