Client HTML + JS pour système de surveillance en ligne



Chez Geektimes, je rencontre souvent et j'aime lire des articles de la série DIY. Ayant décidé d'apporter une petite contribution au trésor d'expériences précieuses réunies ici, je vais décrire en détail le processus de création d'un client pour le web basé sur les serveurs Line.

Le système de surveillance en ligne fournit une API ouverte, et les développeurs disent qu'il est possible d'écrire votre propre client en fonction pour visualiser les archives vidéo et les caméras en ligne. De plus, si vous le souhaitez, vous pouvez implémenter des fonctions telles que l'ajout d'événements à l'archive, la superposition de l'OSD sur la vidéo. Une description de toutes les fonctionnalités est présentée dans les spécifications sur le site officiel .

Cet article est un exemple réel de la façon dont moi, un utilisateur ayant une connaissance initiale de JS, HTML, a écrit ma propre application qui met en œuvre les principes de base de l'utilisation des serveurs de ligne via le serveur Web intégré.

Entrer les données

L'auteur est un débutant dans le développement d'un client HTML, et est impliqué dans le développement du système de vidéosurveillance Line.
Niveau de connaissance de JS, HTML - initial.
La tâche consiste à écrire un client HTML pour travailler avec des appareils basés sur le logiciel Line en utilisant les spécifications du site.

Je vais révéler tout de suite l'intrigue principale - je suis arrivé à deux conclusions:

  1. La spécification est réelle, elle est décrite assez clairement, vous pouvez écrire un client en C ++, PHP.
  2. Vous ne pouvez pas écrire un client HTML à part entière en utilisant uniquement JS - uniquement une surveillance en ligne conformément aux spécifications avant RPC.

La première conclusion est assez logique, étant donné le grand nombre d'intégrations avec des programmes tiers. Tous sont décrits sur le site: il existe des systèmes de contrôle d'accès , de poids , des systèmes POS , des programmes pour déterminer les numéros de voiture et 1C .

La deuxième conclusion est plus intéressante, considérez-la ci-dessous.

Pourquoi ne pouvez-vous pas créer un client à part entière en HTML + JS?


Réponse: demandes interdomaines.

Pour le moment, le serveur Web de la ligne est limité et il est impossible d'obtenir simplement la copie du code dans le dossier www. Cependant, les développeurs promettent que dans la nouvelle version pour Linux et dans "Line 8.0" le serveur web fonctionnera en standard: en cas de demande, s'il y a un fichier, il le renverra.

Créez maintenant un nouveau projet et commencez à coder. Comme tous les nouveaux venus dans la programmation pour le Web, en spécifiant que le serveur "Lines" répond "*" dans l'en-tête Access-Control-Allow-Origin, j'ai commencé à travailler dur sur le code, en vérifiant le résultat sur Firefox 57.0.4 (64 bits). Les demandes au serveur ont été envoyées par XMLHttpRequest.

Dans un premier temps, il serait utile d'étudier les informations sur cette ressource . Tout y est décrit en détail, mais je voulais vraiment terminer rapidement la tâche. Et, malheureusement, faute d'information, une demi-journée s'est perdue sur un coup de tête sur le mur de la politique de sécurité des navigateurs modernes.

Au moment d'écrire ces lignes, quatre principaux navigateurs modernes n'autorisent pas les en-têtes de lecture reçus du serveur. Selon la spécification, il est nécessaire d'implémenter l'authentification Digest, ce qui est impossible sans en-têtes.

À la fin du premier jour, j'ai réalisé que sans ajouter le traitement OPTIONS au serveur Web de la ligne, rien ne fonctionnerait, car pour les demandes avec une méthode «difficile» ou des en-têtes spéciaux, le navigateur fait une pré-demande OPTIONS, en les indiquant dans la méthode de demande de contrôle d'accès et en-têtes de demande de contrôle d'accès. J'ai donc commencé à chercher d'autres options d'autorisation, mais le vrai Basic ou Digest n'a pas décollé.

Une méthode alternative a déjà été décrite dans le cahier des charges, il restait à passer un peu de temps à correspondre avec le département programme de "Lines". Comme de telles difficultés ne surviennent pas pour la première fois, il existe déjà une béquille pour l'autorisation, et elle est même mentionnée dans le cahier des charges:
Sur les clients où il est impossible d'autoriser la demande à l'aide de moyens standard (HTTP Digest / Basic Authentication), l'en-tête Authorization peut être envoyé à l'aide de l'un des paramètres de la demande, par exemple
/kfd3ado1sdrms/streaming/main.flv?authorization=Basic%20d2ViOg==

Après toutes les manipulations, la requête interdomaine standard a commencé à s'exécuter correctement! Il est également nécessaire d'ajouter l'en-tête Accept avec le type correct à la demande - j'ai décidé d'utiliser JSON.

Code de demande:

function get_request_url(method,current_server_data, resource, additional){ var request = current_server_data.server_ip + ':' +current_server_data.port +resource+'?authorization=Basic '+ utf8_to_b64(current_server_data.user+':'+current_server_data.password); if (additional != '' && typeof additional != "undefined") { request += '&' + additional; } return request; } function http_request_of_resource (server_index , resource, auth_attempt) { var request = get_request_url('GET', servers_array[server_index], resource,''); var req_ = new XMLHttpRequest(); req_.open('GET', 'http://'+ request, true); //req_.timeout = 9000; //  ,    req_.onreadystatechange = function() { if (this.readyState == 2) { if (this.status == 401) { //console.log('---unauthorized'); hideModal(); update_nessecary_structure(resource, 'unauthorized', server_index); } } else if (this.readyState === 4) { if (this.status === 0) { hideModal(); update_nessecary_structure(resource, 'server_down',server_index) } if (this.status == 200) { if (auth_attempt) hideModal(); else resource =(resource =='/cameras') ? resource+'_update_info': resource; //console.log('200' + this.responseText); update_nessecary_structure(resource, this.responseText, server_index); } else if (this.status == 404) { //console.log('404'); update_nessecary_structure(resource, '404', server_index); } } }; //   req_.setRequestHeader('Content-type', 'text/plain; charset=utf-8'); req_.setRequestHeader('Accept', 'application/json'); req_.send(); } 

Nous changeons la ressource en celle dont nous avons besoin selon les spécifications et obtenons telle ou telle donnée. La variable supplémentaire contient des paramètres supplémentaires pour la demande, si nécessaire. Sur ce point, le développement de la première moitié de la spécification, à savoir la réception / envoi de données texte via des requêtes GET, peut être considéré comme clos.

De plus, je suis tombé sur le fait que la balise IMG dans IE ne lit pas le flux MJPEG, et vous devez implémenter indépendamment la mise à jour des images des caméras. Le code est ouvert, il peut être consulté et modifié si vous le souhaitez. Dans l'implémentation actuelle, la lecture simultanée d'un maximum de six flux MJPEG est disponible, vous devrez donc faire le travail avec une vue qui affiche plus de caméras. Tout cela est dans l' exemple , si vous le souhaitez, vous pouvez trouver et comprendre, mais si vous avez des questions, assurez-vous de poser dans les commentaires.

Spécification RPC


Nous sommes invités à envoyer et recevoir des données soit en JSON (version du serveur "Lines 7.1.1" et plus) ou MessagePack (version "Line 7.0" et plus). Il est mentionné que MessagePack pèse moins et fonctionne plus rapidement, mais pour être honnête, je choisirais JSON (il est déjà construit en JS), sinon pour une chose mais dans la spécification: la réception de trames de l'archive n'est possible que dans MessagePack. J'ai dû aller sur leur site officiel et télécharger le fichier JS, qui contient les méthodes d'encodage et de décodage.

La fonction d'envoi de demande est prête! Mais il est trop tôt pour célébrer la victoire: lorsque vous essayez de changer l'en-tête de la demande de type de contenu, le navigateur jure et n'envoie pas de données au serveur. Le fait est que le serveur Lines analyse ce champ et l’analyse en fonction du type. Je ne pouvais pas le faire moi-même.

J'ai envoyé une demande au département du programme, et après discussion, ils m'ont ajouté une béquille, comme dans le cas d'une autorisation, - le type de contenu sera transmis dans la demande d'url:

 function rpc_request_of_resource (current_server_data , rpc_method, rpc_request) { var request = get_request_url('POST', current_server_data, '/rpc',''); //console.log("i'm here request = " + request + ' '+ current_server_data.user); request += "&content-type='application/x-msgpack'"; var req_ = new XMLHttpRequest(); req_.open('POST', 'http://'+ request, true); //  ,    req_.responseType = 'arraybuffer'; req_.onreadystatechange = function() { if (this.readyState == 2) { if (this.status == 401) { //console.log('401' + this.getAllResponseHeaders()); console.log('unauthorized'); } } else if (this.readyState == 4) { if (this.status == 200) { //if (auth_attempt) hideModal(); //console.log('200' + this.responseText); rpc_update_nessecary_method(rpc_method, this.response); } else if (this.status == 404) { console.log('404'); } else if (this.status == 500) { //console.log('500'); rpc_update_nessecary_method(rpc_method, '500'); } } }; //   //req_.setRequestHeader('Content-type', 'text/plain; charset=utf-8'); //req_.setRequestHeader('Content-type', 'application/x-msgpack'); req_.setRequestHeader('Accept', 'application/x-msgpack'); req_.send(rpc_request); } 

Cette modification fonctionnera avec la version «Ligne 7.4.1» et supérieure. Pour tous les serveurs sous cette version, le travail avec la ressource / rpc ne sera pas disponible.

Au final, je tiens à remercier tous les clients qui nous ont envoyé des questions / souhaits liés à la mise en œuvre d'applications basées sur notre API. Grâce à vous, une étude a été menée, dans le cadre de laquelle certaines lacunes ont été identifiées et corrigées.

L'exemple décrit dans cet article deviendra progressivement un client HTML à part entière pour Lines. Tout le code sera lisible, vous pouvez le modifier ou l'utiliser comme base pour construire vos propres solutions. L'API, au fil du temps, sera remplie de fonctionnalités encore plus, dont nous informerons certainement.

Source: https://habr.com/ru/post/fr409999/


All Articles