diff --git a/html/connect.html b/html/connect.html
new file mode 100644
index 0000000..04d91b1
--- /dev/null
+++ b/html/connect.html
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
Connect
+
+
+
+
+
+
Enter the address (including rcon port) and the rcon password below to connect.
+
+
+ {{c.Address}}
+
+
+
{{LastErrorMessage}}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/html/console.html b/html/console.html
new file mode 100644
index 0000000..e0a4fb2
--- /dev/null
+++ b/html/console.html
@@ -0,0 +1,22 @@
+
+
+
+
{{line.Message}}
+
+
+
+
\ No newline at end of file
diff --git a/html/players.html b/html/players.html
new file mode 100644
index 0000000..5574634
--- /dev/null
+++ b/html/players.html
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
{{line.DisplayName}}
+
+
+
+
+ {{line.SteamID}} {{line.OwnerSteamID}}
+
+
+
+ {{line.VoiationLevel}}
+
+
+
+ Level: {{line.CurrentLevel}}
+
+
+
+ XP: {{line.UnspentXp}}
+
+
+
+ {{line.Address}}
+
+
+ Ping {{line.Ping}}
+
+
+ {{line.ConnectedSeconds | SecondsToDuration}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/image/arrow-right-bold-hexagon-outline.svg b/image/arrow-right-bold-hexagon-outline.svg
new file mode 100644
index 0000000..2e71c09
--- /dev/null
+++ b/image/arrow-right-bold-hexagon-outline.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/image/menu.svg b/image/menu.svg
new file mode 100644
index 0000000..64844e7
--- /dev/null
+++ b/image/menu.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..9fe5d4e
--- /dev/null
+++ b/index.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+ Websocket Rcon
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{p.Title}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rcon.css b/rcon.css
new file mode 100644
index 0000000..939cb27
--- /dev/null
+++ b/rcon.css
@@ -0,0 +1,47 @@
+H3
+{
+
+}
+
+.AppBackground
+{
+ background-color: #ccc;
+}
+
+.DropShadow
+{
+ box-shadow: 0 1px 8px 0 rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.14),0 3px 3px -2px rgba(0,0,0,.12);
+}
+
+#ConsoleController md-input-container .md-errors-spacer
+{
+ min-height: 0;
+}
+
+#ConsoleController md-input-container
+{
+ margin: 0;
+}
+
+#ConsoleController .Output
+{
+
+ font-size: 16px;
+ white-space: pre-wrap;
+ padding: 8px;
+}
+
+#ConsoleController .Output .Requested
+{
+ color: #2196F3;
+}
+
+#ConsoleController .Output .Chat
+{
+ color: #4CAF50;
+}
+
+#ConsoleController .Input input
+{
+ color: #000;
+}
\ No newline at end of file
diff --git a/rcon.js b/rcon.js
new file mode 100644
index 0000000..863d635
--- /dev/null
+++ b/rcon.js
@@ -0,0 +1,248 @@
+
+
+var app = angular.module('RconApp', ['ngMaterial', 'ngRoute']);
+
+app.config( function( $mdThemingProvider, $routeProvider )
+{
+ $mdThemingProvider.theme('default').primaryPalette('blue').accentPalette('orange');
+
+ $routeProvider.when( "/console", { templateUrl: 'partials/phone-list.html'} )
+ $routeProvider.when( "/players", { templateUrl: 'partials/players.html'} )
+ .otherwise( {redirectTo: '/console'} );
+
+});
+
+app.controller('RconController', RconController);
+
+function RconController( $scope, rconService, $mdSidenav, $timeout, $mdDialog )
+{
+ $scope.pages =
+ [
+ { Name: "console", Title: "Console", Page: "html/console.html" },
+ { Name: "players", Title: "Players", Page: "html/players.html" },
+ ]
+
+ $scope.SwitchPage = function( page )
+ {
+ $scope.CurrentPage = page;
+ }
+
+ $scope.OpenLeftMenu = function()
+ {
+ $mdSidenav('left').toggle();
+ };
+
+ $scope.SwitchPage( $scope.pages[0] );
+
+ $scope.IsConnected = function()
+ {
+ return rconService.IsConnected();
+ }
+
+ rconService.OnOpen = function()
+ {
+ $scope.Connected = true;
+ $scope.$broadcast( "OnConnected" );
+ $scope.$digest();
+ }
+
+ rconService.OnClose = function( ev )
+ {
+ $scope.$broadcast( "OnDisconnected", ev );
+ $scope.$digest();
+ }
+
+ rconService.OnError = function( ev )
+ {
+ $scope.$broadcast( "OnConnectionError", ev );
+ $scope.$digest();
+ }
+
+ rconService.OnMessage = function( msg )
+ {
+ $scope.$broadcast( "OnMessage", msg );
+ }
+}
+
+app.controller('ConnectionController', ConnectionController);
+
+function ConnectionController( $scope, rconService )
+{
+ $scope.Address = "";
+ $scope.Password = "";
+ $scope.SaveConnection = true;
+
+ if ( localStorage.previousConnections != null )
+ $scope.PreviousConnects = angular.fromJson( localStorage.previousConnections );
+
+ if ( $scope.PreviousConnects == null )
+ $scope.PreviousConnects = new Array();
+
+ console.log( $scope.PreviousConnects );
+
+ $scope.Connect = function()
+ {
+ $scope.LastErrorMessage = null;
+ rconService.Connect( $scope.Address, $scope.Password );
+ }
+
+ $scope.ConnectTo = function( c )
+ {
+ $scope.SaveConnection = false;
+ $scope.LastErrorMessage = null;
+ rconService.Connect( c.Address, c.Password );
+ }
+
+ $scope.$on( "OnDisconnected", function( x, ev )
+ {
+ console.log( ev );
+ $scope.LastErrorMessage = "Connection was closed - Error " + ev.code;
+ $scope.$digest();
+ });
+
+ $scope.$on( "OnConnected", function( x, ev )
+ {
+ if ( $scope.SaveConnection )
+ {
+ $scope.PreviousConnects.push( { Address: $scope.Address, Password: $scope.Password } );
+ localStorage.previousConnections = angular.toJson( $scope.PreviousConnects );
+ }
+ });
+}
+
+
+app.controller('ConsoleController', ['$scope', 'rconService', ConsoleController]);
+
+function ConsoleController( $scope, rconService )
+{
+ $scope.Output = new Array();
+
+ $scope.SubmitCommand = function()
+ {
+ rconService.Command( $scope.Command, 1 );
+ $scope.Output.push( { Class: "input", "Message": "> " + $scope.Command } );
+
+ $scope.Command = "";
+ }
+
+ $scope.$on( "OnMessage", function( event, msg )
+ {
+ if ( msg.Message.startsWith( "[CHAT] " ) )
+ msg.Class = "Chat";
+
+ if ( msg.Identifier == 1 )
+ msg.Class = "Requested";
+
+ if ( msg.Identifier > 1 )
+ return;
+
+ $scope.Output.push( msg );
+ $scope.$digest();
+
+ $("#ConsoleController .Output").scrollTop($("#ConsoleController .Output")[0].scrollHeight);
+
+ });
+}
+
+
+app.controller('PlayersController', ['$scope', 'rconService', PlayersController]);
+
+function PlayersController( $scope, rconService )
+{
+ $scope.Output = new Array();
+
+ $scope.Refresh = function()
+ {
+ rconService.Command( "playerlist", 2 );
+ }
+
+ $scope.$on( "OnConnected", function( event )
+ {
+ $scope.Refresh();
+ });
+
+ $scope.$on( "OnMessage", function( event, msg )
+ {
+ if ( msg.Identifier != 2 )
+ return;
+
+ $scope.Players = JSON.parse( msg.Message );
+ });
+
+
+}
+
+
+app.service('rconService', [RconService]);
+
+function RconService()
+{
+ var s = {};
+
+ s.Connect = function( addr, pass )
+ {
+ s.Socket = new WebSocket( "ws://" + addr + "/" + pass );
+
+ s.Socket.onmessage = function (e)
+ {
+ if (s.OnMessage != null)
+ {
+ s.OnMessage( JSON.parse( e.data ) );
+ }
+ };
+
+ s.Socket.onopen = s.OnOpen;
+ s.Socket.onclose = s.OnClose;
+ s.Socket.onerror = s.OnError;
+
+ console.log( s.Socket );
+ }
+
+ s.Command = function( msg, identifier )
+ {
+ if (identifier == null)
+ identifier = -1;
+
+ var packet =
+ {
+ Identifier: identifier,
+ Message: msg,
+ Name: "WebRcon"
+ }
+
+ s.Socket.send( JSON.stringify( packet ) );
+ };
+
+ s.IsConnected = function()
+ {
+ if ( s.Socket == null ) return false;
+ console.log( s.Socket );
+
+ return true;
+ }
+
+ return s;
+}
+
+app.filter('SecondsToDuration', [SecondsToDuration]);
+
+function SecondsToDuration()
+{
+ return function ( input )
+ {
+ input = parseInt( input );
+
+ var out = "";
+ var hours = Math.floor(input / 3600);
+ if ( input > 3600 ) out += hours + "h ";
+
+ var minutes = Math.floor(input / 60) % 60;
+ if ( input > 60 ) out += minutes + "m ";
+
+ var seconds = input % 60;
+ out += seconds + "s";
+
+ return out;
+ }
+}
+
\ No newline at end of file