Błąd "Cannot read property 'emit' of undefined"

0

Cześć.
Spojrzę do tego jeszcze jutro ale zadam pytanie bo już zmęczył mnie ten task :)

Chcę przesłać dane na kanał, ale otrzymuję poniższy błąd.
Co robię źle i gdzie może być błąd?
Proszę o podpowiedź.
Miłej nocki życzę :)

app.post("/message", jsonParser, (request, response) => {
  
  if (request.body.password !== serverKey) {
    console.log("bad password " + request.body.password);
    response.statusCode = 500;
    return response.end("NO U");
  }
  console.log(request.body);
  if (typeof request.body.chanName === "string") {
    sockets[request.body.chanName].emit("message", {message: request.body.message,info: request.body.info});
  } else {
    for (var i in request.body.chanName) {
      sockets[request.body.chanName[i]].emit("message", {message: request.body.message,info: request.body.info});
    }
  }

  response.writeHead(200);
  response.end("Dziń dybry");
});
Database connection
user connected 15
{
  chanName: 'worldchat5',
  message: 'cscscscs',
  info: {
    chanType: 'world',
    msgDate: '16/08/2022 22:15:51',
    nationID: '1',
    login: 'miccom',
    playerID: '15'
  },
}
TypeError: Cannot read property 'emit' of undefined
0

Nie wiem, w której dokładnie linijce to masz (bo masz 2 linijki, w którym ten błąd mógłby wystąpić)

Node.js Cannot read property 'emit' of undefined

zakładając, że to ta linijka:

sockets[request.body.chanName].emit("message", {message: request.body.message,info: request.body.info});

znaczy to, że sockets[request.body.chanName] jest undefined.

    for (var i in request.body.chanName) {
      sockets[request.body.chanName[i]].emit("message", {message: request.body.message,info: request.body.info});
    }

ew. że któreś z wyrażeń sockets[request.body.chanName[i]] w pętli daje w rezultacie undefined.

Czyli innymi słowy w obiekcie (albo tablicy? co tam masz?) sockets nie ma odpowiedniego obiektu.

Tylko, że na tym kawałku kodu, który wkleiłeś, nie widać czym jest to sockets.
Weź zrób gdzieś console.log(sockets) i zobacz, czy w sockets znajdują się te kanały
Tak samo console.log(request.body.chanName) żeby było widać, jakie masz dokładnie tam klucze.

if (typeof request.body.chanName === "string") {

Czy będą sytuacje, kiedy ten warunek nie będzie prawdą? Skąd dostajesz to chanName? Czy to jest przesyłane od użytkownika (jeśli tak, czy jest to jakoś deserializowane ze stringa?) Czy jest to ustawiane w middleware?

0

Oki, więc takie zgłoszenie mam od nodemona

[nodemon] starting `node app.js`
Database connection
user connected 15
Gracz dolaczyl do gry - swiat:5, nacja:1, uid:15
{
  '15': [
    Socket {
      _events: [Object: null prototype],
      _eventsCount: 5,
      _maxListeners: undefined,
      nsp: [Namespace],
      client: [Client],
      data: {},
      connected: true,
      acks: Map(0) {},
      fns: [],
      flags: {},
      server: [Server],
      adapter: [Adapter],
      id: '9K1j_9Y7pD9Vf3MPAAAA',
      handshake: [Object],
      [Symbol(kCapture)]: false
    }
  ]
}



Kod który to generuje to:

function (err, rows) {
          if (err) {
            console.error(
              "error connecting (sid " + req.ident + "): " + err.stack
            );
            return;
          }

          if (rows.length !== 0) {
            if (rows[0].length === 0) return;

            var userData = rows[0];
            // join main world chat room
            console.log(
              "Gracz dolaczyl do gry - swiat:" +
                userData.worldID +
                ", nacja:" +
                userData.nation +
                ", uid:" +
                userData.uid
            );
    
            socket.join("worldchat" + userData.worldID);
            // join nation chat
            socket.join("worldchat" + userData.worldID + "nation" + userData.nation);
            // join private chat
            socket.join("worldchat" + userData.worldID + "private" + userData.uid);
            // join world map data
            socket.join("worldmap" + userData.worldID + "nation" + userData.nation);

            console.log(sockets);

A przy wysłaniu na ten adres post generuję:

chanName worldchat5
{
  '15': [
    Socket {
      _events: [Object: null prototype],
      _eventsCount: 5,
      _maxListeners: undefined,
      nsp: [Namespace],
      client: [Client],
      data: {},
      connected: true,
      acks: Map(0) {},
      fns: [],
      flags: {},
      server: [Server],
      adapter: [Adapter],
      id: '9K1j_9Y7pD9Vf3MPAAAA',
      handshake: [Object],
      [Symbol(kCapture)]: false
    }
  ]
}
TypeError: Cannot read property 'emit' of undefined
    at C:\xampp\htdocs\project\app.js:181:36

A całe zdarzenie:

app.post("/message", jsonParser, (request, response) => {
  // err is probably an invalid json error
  if (request.body.password !== serverKey) {
    console.log("bad password " + request.body.password);
    response.statusCode = 500;
    return response.end("NO U");
  }
  console.log('chanName',request.body.chanName);
  console.log(sockets);
  if (typeof request.body.chanName === "string") {
    181 line: sockets[request.body.chanName].emit("message", {message: request.body.message, info: request.body.info});
  } else {
    for (var i in request.body.chanName) {
      sockets[request.body.chanName[i]].emit("message", {message: request.body.message, info: request.body.info});
    }
  }

  response.writeHead(200);
  response.end("Dziń dybry");
});

Czyli wychodzi na to, że kanał jest zadeklarowany (worldchat5) , ale nie ma go w obiekcie sockets{} :(

Ten socket '15' to mój idik zadeklarowany tutaj:

io.on("connection", function (socket) {
  if (!sockets[socket.handshake.query.user_id]) {
    sockets[socket.handshake.query.user_id] = [];
  }
  sockets[socket.handshake.query.user_id].push(socket);
1

Czyli wychodzi na to, że kanał jest zadeklarowany (worldchat5) , ale nie ma go w tablicy sockets{} :(

Nie wiem, czy to był skrót myślowy, czy nie, ale wg tego kodu sockets nie jest tablicą, tylko obiektem, który zawiera klucz '15' pod którym dopiero znajduje się tablica.

io.on("connection", function (socket) {
  if (!sockets[socket.handshake.query.user_id]) {
    sockets[socket.handshake.query.user_id] = [];
  }
  sockets[socket.handshake.query.user_id].push(socket);

czy to jest jedyny kod, który jest odpowiedzialny za dodawanie socketów do sockets?
Jeśli tak, to user_id musiałoby być równe "worldchat5", bo wtedy dopiero ten kod:

  sockets[socket.handshake.query.user_id] = [];

robiłby to:

 sockets["worldchat5"] = [];

(chyba, że coś tam się dzieje jeszcze gdzie indziej w związku z sockets).

No i tak, koncepcyjnie/potencjalnie masz taką strukturę danych - obiekt z tablicami w środku:

{
    klucz1: [socket, socket, socket],
    klucz2: [socket, socket, socket],     
}

natomiast robiąc emit traktujesz go jak obiekt z socketami w środku:

sockets[chanName].emit(........)

czyli nawet jak rozwiążesz ten problem z undefined, to i tak nie powinno zadziałać, bo sockets[chanName] nawet jak nie będzie undefined, to będzie tablicą socketów, a nie socketem.

0

Zgodnie z Twoimi słowami postanowiłem wyrzucić ten obiekt dla socketów i bezpośrednio łączyć się z socketami- a to wystarczy zrobić jako socket.join('wolrdMap5') a potem już emitować dane do tego kanału :)

Wczoraj byłem już zmęczony, a dzisiaj jakby nowe siły :) i chęci do czytania dokumentacji :)
https://socket.io/docs/

I poszło, pięknie działa, przez co ja pięknie dziękuję za podpowiedź @LukeJL :)


.....

sockets: [Map],
      _fns: [],
      _ids: 0,
      server: [Server],
      name: '/',
      adapter: [Circular *4],
      [Symbol(kCapture)]: false
    },
    rooms: Map(5) {
      'kC9c2L2gpAcrmMyrAAAA' => [Set],
      'worldchat5' => [Set],
      'worldchat5nation1' => [Set],
      'worldchat5private15' => [Set],
      'worldmap5nation1' => [Set]
    },
    sids: Map(1) { 'kC9c2L2gpAcrmMyrAAAA' => [Set] },
    encoder: Encoder {},
    [Symbol(kCapture)]: false
  },
  id: 'kC9c2L2gpAcrmMyrAAAA',
  handshake: {
    headers: {
      host: 'localhost:3000',
      connection: 'keep-alive',
      'sec-ch-ua': '"Chromium";v="104", " Not A;Brand";v="99", "Google Chrome";v="104"',
      accept: '*/*',
      dnt: '1',
      'sec-ch-ua-mobile': '?0',
      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
      'sec-ch-ua-platform': '"Windows"',
      origin: 'http://localhost:8020',
      'sec-fetch-site': 'same-site',
      'sec-fetch-mode': 'cors',
      'sec-fetch-dest': 'empty',

      ....

1 użytkowników online, w tym zalogowanych: 0, gości: 1