Управляем компьютером через браузер

в 9:58, , рубрики: ajax, css, css3, html, html5, javascript, pc-control, php, remote control, web-разработка

Компьютер давно многим заменил телевизор, а что не хватает компьютеру для комфортного просмотра кино, сериалов и прочего? Мне лично не хватало пульта дистанционного управления.

image


Я не много увлекаюсь веб-программированием в свободное время. Было решено написать свой велосипед и заодно совместить приятное с полезным. Была изучена возможность с помощью консоли управлять компьютером, в первую очередь меня интересовал следующий минимальный объем задач (который немного увеличился в последствии):

  • Возможность отправить ПК в режим сна
  • Возможность выключить громкость

С помощью известного поисковика нашел консольную программу, NirCmd, программа позволяет осуществлять достаточно много действий кроме указанных выше. С основной частью мы определились. Как я говорил, не много изучаю php, веб-сервер у меня как правило запущен постоянно, поэтому ничего специфичного в плане сервера я придумывать не стал. Сервер написан на php и состоит из двух классов: Control, который представляет собой методы которые исполняют консольные команды и Route, который делает валидацию приходящих запросов и исполняет методы класса Control.

Control выгладит вот так (код однотипный, поэтому я сократил):

class Control implements ActionControl {
		protected $Path; //путь до программы nirCmd;
		
		function __construct($p = 'C:/nircmd/nircmd.exe') {
			$this->Path = $p;
		}
		function standby() {
			`{$this->Path} standby`;
		}
		function hibernate() {
			`rundll32 powrprof.dll,SetSuspendState 0,1,0`;
		}
		function reboot() {
			`{$this->Path} exitwin reboot`;
		}
		function turnOff() {
			`{$this->Path} exitwin poweroff`;
		}
		function logout() {
			`{$this->Path} exitwin logoff`;
		}
}

Второй класс, — Route. Собственно к нему обращается клиент. Класс, в первую очередь осуществляет валидацию запроса, и если запрос правильный вызывает методы класса Control.
Выглядит это так:

class Route implements ActionRoute {
		protected $possible = []; 		
		protected $ControlObj;
	
		function __construct($obj) {
			$this->possible = get_class_methods($obj); 
			$this->ControlObj = $obj;
		}
		function route($arr) { 
			forEach($arr as $key => $value) {	
		   if (in_array($key, $this->possible) && $value == 'true') {
		   	$this->execute($key);
		   } else 
		   	{
		   		Message::sent('wrong method');
		   	}	
			}
		}
		function execute($c) {
			$this->ControlObj->$c();
			Message::sent('executed');
		}
	}

Чтобы получилось в случае чего легко расширить количество методов в классе Control, валидация в классе Route жестко не привязана к определенному списку методов класса Control, точнее привязана, но все возможные методы извлекаются из самого объекта, с ними и идет сравнение пришедших данных.

Сам файл к которому обращается клиент выглядит вот так:

<?
	define("PATH", "C:/nircmd/nircmd.exe"); 
	function __autoload($name) {
		require "class/$name.class.php";
	}
	
	$obj = new Control(PATH);
	$route = new Route($obj);

	if ($_GET) {
		$route->route($_GET);
	}
?>

Если приходит GET запрос, то весь массив отдаем методу route.

Клиентская часть представляет собой кнопки управления и один обработчик, по которому мы шлем данные при помощи ajax на сервер.

var wrapper = document.querySelector(".wrapper");

function getXmlHttpRequest(){
	if (window.XMLHttpRequest) {
		try {
			return new XMLHttpRequest();
		} catch (e){ }
	} else if (window.ActiveXObject) {
		try {
			return new ActiveXObject('Msxml2.XMLHTTP');
		} catch (e){}
		try {
			return new ActiveXObject('Microsoft.XMLHTTP');
		} catch (e){}
		}
	return null;
}

wrapper.addEventListener('click', function(e){
	var target = e.target;

	if(target.tagName!= 'BUTTON') return;
	if (target.getAttribute('data')=='qestion') {
		var yn = confirm("Уверен?");
		if (!yn) return
			ajaxf(target.id);
	}
	ajaxf(target.id);
})

	function ajaxf($com) {
	 	var command = $com+'=true';
		var xhr = new getXmlHttpRequest();
		xhr.open('GET', 'remote.php?'+command, true);
		xhr.send();
		xhr.onreadystatechange = function() { 
  			if (xhr.readyState != 4) return;
  			if (xhr.status != 200) {
    			console.log(xhr.status + ': ' + xhr.statusText);
  			} else {
   	 		console.log(xhr.responseText);
  			}
		}
	}

На сегодня реализован следующий функционал управления:

  • спящий режим
  • гибернация
  • перезагрузится
  • выключить
  • выйти
  • выключить монитор
  • включить/отключить звук по триггеру
  • громкость больше
  • громкость меньше
  • Медиа кнопки, stop/play next/prev

Все, что я хотел получить, получил, но, как говорится, аппетит приходит во время еды. Хотелось бы иметь обратную связь от сервера, т.е. при первом заходе на страницу делать запрос текущего уровня громкости например. К сожалению, nirCmd не возвращает значения при выполнении, поэтому с тем, что имеем сейчас, я не знаю, как это осуществить.

Вопрос безопасности. Хотя это все и крутится на локальной машине, будет очень печально, если доступ к исполнению команд nirCmd будет у злоумышленника, т.к. можно сотворить много деструктивных действий.

Готовый проект на GIthab.

Автор: Sad_Bro

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js