• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Odpowiednik obiektu window dla node.js [React, Express]

Object Storage Arubacloud
0 głosów
376 wizyt
pytanie zadane 6 kwietnia 2021 w JavaScript przez Oskar Szkurłat Bywalec (2,780 p.)
zamknięte 6 kwietnia 2021 przez ScriptyChris

Cześć, posiadam stronę internetową wykonaną w React postawioną za pomocą Express w aplikacji node.js. Zrobiłem sobie proste sterowanie głosowe za pomocą wbudowanego obiektu w przeglądarkę {window}. Aplikacja sama w sobie działa, jak wystawiam serwer react lokalnie (npm start), tzn. wykrywa mikrofon, przechwytuje dźwięk i zwraca za pomocą google speech recognition string, który steruje stroną. Jednak problem się pojawia, gdy stronę już stawiam za pomocą Express na aplikacji node.js. Funkcja przycisku i zmiany stanu (kolor przycisku) w react się wykonuje, jednak rec.start() nie uruchamia się. Myślałem szczerze, że skoro otwieram stronę hostowaną z aplikacji node.js, to obiekt window jest wbudowany w przeglądarkę, w której otwiera się. Więc pytanie: czy istnieje jakiś sposób przebudowania (odniesienia się do obiektu window) bez przebudowywania całego softu nasłuchu i odpowiedzi, który już sobie przygotowałem? Znalazłem również biblioteki dla node.js do przetwarzania mowy (np. react-speech-recognition), ale nie sprawdzałem jeszcze ich, bo może udałoby się bez zmieniania za bardzo kodu uruchomić standardowy {window}? Jeżeli nie ma takiej możliwości, to czy jest ktoś w stanie mi polecić sprawdzoną bibliotkę opartą o zewnętrzną chmurę (jak np. google)?

import React, { useState } from 'react'
import { Button } from 'reactstrap'
import { Mic } from 'react-bootstrap-icons'
import cmds from './commands'

const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition

class Controller extends React.Component {
    constructor(props) {
        super(props)
        this.rec = new SpeechRecognition()
        this.rec.lang = 'pl-PL'
        this.rec.onstart = () => { console.log("Listening...") }
        this.rec.onresult = async event => {
            const current = event.resultIndex
            const transcript = event.results[current][0].transcript
            await cmds.readOut(transcript)
        }
        this.rec.onend = async () => {
            await this.rec.abort()
            await this.rec.stop()
            if (this.state.bttnColor === 'danger')
                await this.rec.start()
        }
        this.state = {
            bttnColor: 'primary'
        }
    }
    async startListening() {
        await this.rec.abort()
        await this.rec.stop()
        if (this.state.bttnColor === 'danger')
            await this.rec.start()
    }
    render() {
        return (
            <>
                <Button style={{ float: 'right' }} color={this.state.bttnColor}
                    onClick={async () => {
                        await this.setState({ bttnColor: this.state.bttnColor === 'primary' ? 'danger' : 'primary' });
                        await this.startListening()
                    }}
                ><Mic color="white" /></Button>
            </>
        )
    }
}
import axios from 'axios'

const commands = {
    states: [
        { state: false, ref: '/upCmd', lastType: '' },
        { state: false, ref: '/downCmd', lastType: '' },
        { state: false, ref: '/leftCmd', lastType: '' },
        { state: false, ref: '/rightCmd', lastType: '' }
    ],
    _voiceHandler: async cmd => {
        console.log('cmd', cmd)
        let response
        switch (cmd.toLowerCase()) {
            case 'jedź': case 'przed siebie': case 'przód': case 'prosto': case 'do przodu': case 'jedź przed siebie':
                response = 'jadę prosto'
                await axios.post('/upCmd', { state: true }); break
            case 'skręć w lewo': case 'lewo': case 'w lewo':
                response = 'skręcam w lewo'
                await axios.post('/leftCmd', { state: true }); break
            case 'skręć w prawo': case 'prawo': case 'w prawo':
                response = 'skręcam w prawo'
                await axios.post('/rightCmd', { state: true }); break
            case 'cofaj': case 'tył': case 'do tyłu':
                response = 'cofam'
                await axios.post('/downCmd', { state: true }); break
            case 'stop': case 'zatrzymaj się': case 'stój': case 'nie ruszaj się':
                response = 'zatrzymuję się'
                await axios.post('/upCmd', { state: false })
                await axios.post('/leftCmd', { state: false })
                await axios.post('/rightCmd', { state: false })
                await axios.post('/downCmd', { state: false })
                break
        } //await before axioses blocks response speech text without answer
        if (response === undefined) response = 'nie rozumiem'
        return response
    },
    readOut: async message => {
        const speech = new SpeechSynthesisUtterance()
        speech.text = await commands._voiceHandler(message)
        speech.volume = 1
        speech.rate = 1
        speech.pitch = 1
        speech.lang = 'pl-PL'
        window.speechSynthesis.speak(speech)
    }
}
export default commands

Z góry dziękuję.

komentarz zamknięcia: Problem rozwiązany - przyczyną był brak HTTPS.
2
komentarz 6 kwietnia 2021 przez ScriptyChris Mędrzec (190,190 p.)

Aplikacja sama w sobie działa, jak wystawiam serwer react lokalnie (npm start)

 +

 Jednak problem się pojawia, gdy stronę już stawiam za pomocą Express na aplikacji node.js

Jeśli w obu przypadkach serwujesz apkę z Node, ale jej logika wykonywana jest w przeglądarce, to nie bardzo widzę powód, dla którego window miało by być niedostępne.

Myślałem szczerze, że skoro otwieram stronę hostowaną z aplikacji node.js, to obiekt window jest wbudowany w przeglądarkę, w której otwiera się

Tak, window to obiekt dostępny w przeglądarce, który reprezentuje globalne API (w tym zmienne globalne). W Node jest to global. Natomiast od pewnego czasu jest też uniwersalny (cross platformowy) obiekt globalThis, którego możesz użyć, z tym że inne runtime'y niż przeglądarka mogą nie udostępniać tych samych API (jak np. SpeechRecognition).

Może coś w kodzie rzuca błąd niezwiązany z window i dlatego dalszy kod nie działa?

2 odpowiedzi

0 głosów
odpowiedź 6 kwietnia 2021 przez rafal.budzis Szeryf (85,260 p.)

Jeśli w Express robisz renderowanie strony to nic dziwnego że masz błędy. Jednak nie dałeś kodu Expressa więc trudno powiedzieć. Jeśli chcesz robić SSR to musisz sprawdzać czy obiekt window istnieje. Jeśli istnieje wykonujesz kod (bo jesteś w przeglądarce) jeśli nie istnieje to pomijasz (bo do SSR window nie jest Ci potrzebny).

Warto mieć na uwadze ze rozpoznawanie mowy działa obecnie tylko na chrome. 
https://caniuse.com/speech-recognition

Jeśli to podstawowa funkcja która musi działać na produkcji to powinieneś stworzyć własny mechanizm. Najlepiej oparty o usługę chmurową tak jak wspomniałeś. 

0 głosów
odpowiedź 6 kwietnia 2021 przez Oskar Szkurłat Bywalec (2,780 p.)
edycja 6 kwietnia 2021 przez Oskar Szkurłat

Jest jeszcze dziwniej, niż się spodziewałem, z tego co zauważyłem, to nie jest problemem kod (ale miło się dowiedzieć o globalThis, bo raczej tak to powinno być zamiast window). Źle zdiagnozowałem problem :). To przeglądarka Chrome (i mobilna i pc) blokuje. Strona oczywiście ma status niezabezpieczona i przeglądarka, mimo że chciałbym dodać adres do wyjątków ma totalnie wywalone na moją konfigurację (nie mogę zmienić dostępu na zezwalaj, bo 'prywatność'). Wyłączenie jakikolwiek zabezpieczeń dalej nie pozwalało mi dostać się do mikrofonu na własnej stronie z mojego wifi xd.

Obstawiałem, że to kwestia braku SSL i łączenia się protokołem http, zamiast https. I jak się okazało dobrze obstawiłem - musiałem zaimplementować https w expressie. Zrobiłem to zgodnie z poradnikiem. Kod dla potomnych:

//___________ Libraries ___________
const fs = require('fs')
const key = fs.readFileSync('./key.pem')
const cert = fs.readFileSync('./cert.pem')
const express = require('express')
const https = require('https')
const bodyParser = require('body-parser')
const app = express()
const path = require('path')
//___________ Configuration ___________
const server = https.createServer({ key: key, cert: cert }, app)
const port = require('../config/config').SERVER.PORT
const PORT = process.env.PORT || port
app.set('views', path.join(__dirname, '..', 'frontend', 'build'))
app.set('view engine', 'hbs')
app.use(express.static(path.join(__dirname, '..', 'frontend', 'build')))
//___________ My files ___________
const routes = require('./routes/index')
//___________ Parsers ___________
app.use(bodyParser.json())
app.use(bodyParser.raw());
app.use(bodyParser.urlencoded({ extended: true }));
//___________ Routes ___________
app.use('/', routes)

server.listen(PORT, () => { console.log(`Listening server at port [${PORT}]`) })

I taka ciekawostka, która może komuś się kiedyś przydać: websocket w momencie przejścia z protokołu http na https wymaga przejścia z 'ws' na 'wss'. (Moja aplikacja pracuje na obu z pewnych względów).
 

const W3CWebSocket = require('websocket').w3cwebsocket
const client = new W3CWebSocket('wss://' + IP + ':8081')
const WebSocket = require('wss')
const port = require('../config/config').SERVER.ASYNC_PORT
const wss = WebSocket.createServer()
const httpsCreateServer = require('https').createServer
const https = httpsCreateServer()
https.listen(port)

Myślę, że temat wyczerpany i do zamknięcia. Dziękuję za odpowiedzi.

Podobne pytania

+2 głosów
1 odpowiedź 320 wizyt
pytanie zadane 23 czerwca 2021 w JavaScript przez poldeeek Mądrala (5,980 p.)
+1 głos
1 odpowiedź 729 wizyt
+1 głos
2 odpowiedzi 2,152 wizyt
pytanie zadane 18 listopada 2018 w JavaScript przez lolson Nowicjusz (130 p.)

92,570 zapytań

141,422 odpowiedzi

319,643 komentarzy

61,958 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...