Peerjs: 연결이 끊긴 ν›„ peer.jsλŠ” μ–΄λ–»κ²Œ λ™μΌν•œ 피어에 λ‹€μ‹œ μ—°κ²°ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

에 λ§Œλ“  2020λ…„ 04μ›” 14일  Β·  7μ½”λ©˜νŠΈ  Β·  좜처: peers/peerjs

μš°λ¦¬κ°€ λ©”μ‹œμ§€λ₯Όλ°›μ„ λ•Œ 2 개의 ν”Όμ–΄κ°€ 톡화에 μ—°κ²°λ˜μ–΄ μžˆλŠ”μ§€ μ•Œμ•„μ•Όν•©λ‹ˆλ‹€. μ•„μ΄μŠ€ μ—°κ²° μƒνƒœκ°€ μ—°κ²° ν•΄μ œλ˜λ©΄ λͺ¨λ“  μ°½κ³Ό dicsonnect 2 ν”Όμ–΄κ°€ λ‹«νž™λ‹ˆλ‹€. μ•„μ΄μŠ€ μ„œλ²„ 연결이 λŠκ²Όμ„ λ•Œ 재 연결을 처리 ν•  수 β€‹β€‹μžˆμŠ΅λ‹ˆκΉŒ?

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

μ•„μ΄μŠ€ 컀λ„₯μ…˜ 연결이 λŠμ–΄μ‘Œμ„ λ•Œ μ–΄λ–»κ²Œ λ‹€μ‹œ μ—°κ²°ν•  수 μžˆλŠ”μ§€ μ•Œκ³  μ‹ΆμŠ΅λ‹ˆλ‹€. λ„ˆλ¬΄ λ§Žμ€ μ½”λ“œλ₯Ό μ‹œλ„ν–ˆμ§€λ§Œ μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

이 λΌμ΄λΈŒλŸ¬λ¦¬λŠ” 연결을 μ¦‰μ‹œ λ‹«κΈ° λ•Œλ¬Έμ— 연결이 끊긴 μƒνƒœμ˜ 정상 볡ꡬλ₯Ό μˆ˜ν–‰ ν•  수 μ—†μŠ΅λ‹ˆλ‹€. ν•  μˆ˜μžˆλŠ” μœ μΌν•œ 방법은 on('error') 을듀은 λ‹€μŒ μ›λž˜ 연결을 μ„€μ •ν•  λ•Œμ™€ λ˜‘κ°™μ€ λ°©μ‹μœΌλ‘œ μ—°κ²°ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. κ½€ 고톡 μŠ€λŸ½μŠ΅λ‹ˆλ‹€.

μ°Έκ³  : 였λ₯˜λ₯Ό 확인할 μˆ˜μžˆλŠ” 두 곳이 μžˆμŠ΅λ‹ˆλ‹€. ν”Όμ–΄ 자체 및 μ—°κ²° 자체. μ—°κ²° 상, 그듀은이 λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ§€κΈˆκ³Ό 같은 λ°©μ‹μœΌλ‘œ 거의 λͺ¨λ‘ 치λͺ…μ μž…λ‹ˆλ‹€. ν”Όμ–΄ μžμ²΄μ—μ„œ λ§Žμ€ 였λ₯˜κ°€ 치λͺ…μ μ΄μ§€λ§Œ μ „λΆ€λŠ” μ•„λ‹™λ‹ˆλ‹€.

ν”Όμ–΄μ˜ μ†ŒμΌ“ 였λ₯˜μ˜ 경우 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

this.peer.on('disconnected', () => {
        this.disconnectBackoff = 1;
        this.retrySocketConnection();
      });

μ—¬κΈ°μ„œ λ°± μ˜€ν”„λŠ” μ΅œλŒ€ 값에 도달 ν•  λ•Œλ§ˆλ‹€ μ¦κ°€ν•˜λŠ” 초 λ‹¨μœ„μ˜ κ°’μž…λ‹ˆλ‹€.

ν”Όμ–΄ 였λ₯˜μ˜ 경우 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

// Non-Fatal error:
// 'peer-unavailable' = maybe they left?
// 'disconnected' = this means the Peering server disconnected, we have a seperate retry for that on('disconnect')
// pretty much all of the rest are fatal.
const FATAL_ERRORS = ['invalid-id', 'invalid-key', 'network', 'ssl-unavailable', 'server-error', 'socket-error', 'socket-closed', 'unavailable-id', 'webrtc'];
this.peer.on('error', (e) => {
        if (FATAL_ERRORS.includes(e.type)) {
          this.reconnectTimeout(e); // this function waits then tries the entire connection over again
        } else {
          console.log('Non fatal error: ',  e.type);
        }
      });

그리고 μ—°κ²° (제 κ²½μš°μ—λŠ” mediaConnection)에 λŒ€ν•΄ 이것을 가지고 μžˆμŠ΅λ‹ˆλ‹€.

call.on('error', (e) => {
      console.warn('error with stream', e);
      if (initiator) { // initiator is a value I set myself
        // Optionally this should call only the user that failed instead of the whole thing
        this.reconnectTimeout();
      }
    });

그리고 μ•žμ„œ μ–ΈκΈ‰ ν•œ reconnectTimeout λŠ” 전체 연결을 λ‹€μ‹œ μ‹œλ„ν•˜λŠ” κ°„λ‹¨ν•œ ν•¨μˆ˜μž…λ‹ˆλ‹€.

이둠적으둜이 λΌμ΄λΈŒλŸ¬λ¦¬λŠ” iceRestarts 처리 ν•  수 β€‹β€‹μžˆμœΌλ©° μ•„μ΄μŠ€ λ””μŠ€ 컀λ„₯νŠΈμ—μ„œ 치λͺ…적이지 μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. 이것은 λŒ€λΆ€λΆ„μ˜ 문제λ₯Ό ν•΄κ²°ν•  것이라고 λ―ΏμŠ΅λ‹ˆλ‹€. μ—°κ²° ν•΄μ œμ— λŒ€ν•œ PR이 μžˆμ§€λ§Œ 아직 λ‹€μ‹œ μ‹œμž‘ν•˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€.

λͺ¨λ“  7 λŒ“κΈ€

연결이 λŠμ–΄μ§„ μƒνƒœλŠ” 볡ꡬ ν•  수 μžˆμ–΄μ•Όν•˜μ§€λ§Œ ν˜„μž¬μ΄ λΌμ΄λΈŒλŸ¬λ¦¬λŠ” 연결을 λ„ˆλ¬΄ 일찍 λ‹«μŠ΅λ‹ˆλ‹€. 그것이 처리 될 λ•ŒκΉŒμ§€ μ΅œμ„ μ˜ 방법은 타이머λ₯Ό 였λ₯˜μ— 놓고 λ‹€μ‹œ μ—°κ²°ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

μ•„μ΄μŠ€ 컀λ„₯μ…˜ 연결이 λŠμ–΄μ‘Œμ„ λ•Œ μ–΄λ–»κ²Œ λ‹€μ‹œ μ—°κ²°ν•  수 μžˆλŠ”μ§€ μ•Œκ³  μ‹ΆμŠ΅λ‹ˆλ‹€. λ„ˆλ¬΄ λ§Žμ€ μ½”λ“œλ₯Ό μ‹œλ„ν–ˆμ§€λ§Œ μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ•„μ΄μŠ€ 컀λ„₯μ…˜ 연결이 λŠμ–΄μ‘Œμ„ λ•Œ μ–΄λ–»κ²Œ λ‹€μ‹œ μ—°κ²°ν•  수 μžˆλŠ”μ§€ μ•Œκ³  μ‹ΆμŠ΅λ‹ˆλ‹€. λ„ˆλ¬΄ λ§Žμ€ μ½”λ“œλ₯Ό μ‹œλ„ν–ˆμ§€λ§Œ μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

이 λΌμ΄λΈŒλŸ¬λ¦¬λŠ” 연결을 μ¦‰μ‹œ λ‹«κΈ° λ•Œλ¬Έμ— 연결이 끊긴 μƒνƒœμ˜ 정상 볡ꡬλ₯Ό μˆ˜ν–‰ ν•  수 μ—†μŠ΅λ‹ˆλ‹€. ν•  μˆ˜μžˆλŠ” μœ μΌν•œ 방법은 on('error') 을듀은 λ‹€μŒ μ›λž˜ 연결을 μ„€μ •ν•  λ•Œμ™€ λ˜‘κ°™μ€ λ°©μ‹μœΌλ‘œ μ—°κ²°ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. κ½€ 고톡 μŠ€λŸ½μŠ΅λ‹ˆλ‹€.

μ°Έκ³  : 였λ₯˜λ₯Ό 확인할 μˆ˜μžˆλŠ” 두 곳이 μžˆμŠ΅λ‹ˆλ‹€. ν”Όμ–΄ 자체 및 μ—°κ²° 자체. μ—°κ²° 상, 그듀은이 λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ§€κΈˆκ³Ό 같은 λ°©μ‹μœΌλ‘œ 거의 λͺ¨λ‘ 치λͺ…μ μž…λ‹ˆλ‹€. ν”Όμ–΄ μžμ²΄μ—μ„œ λ§Žμ€ 였λ₯˜κ°€ 치λͺ…μ μ΄μ§€λ§Œ μ „λΆ€λŠ” μ•„λ‹™λ‹ˆλ‹€.

ν”Όμ–΄μ˜ μ†ŒμΌ“ 였λ₯˜μ˜ 경우 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

this.peer.on('disconnected', () => {
        this.disconnectBackoff = 1;
        this.retrySocketConnection();
      });

μ—¬κΈ°μ„œ λ°± μ˜€ν”„λŠ” μ΅œλŒ€ 값에 도달 ν•  λ•Œλ§ˆλ‹€ μ¦κ°€ν•˜λŠ” 초 λ‹¨μœ„μ˜ κ°’μž…λ‹ˆλ‹€.

ν”Όμ–΄ 였λ₯˜μ˜ 경우 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

// Non-Fatal error:
// 'peer-unavailable' = maybe they left?
// 'disconnected' = this means the Peering server disconnected, we have a seperate retry for that on('disconnect')
// pretty much all of the rest are fatal.
const FATAL_ERRORS = ['invalid-id', 'invalid-key', 'network', 'ssl-unavailable', 'server-error', 'socket-error', 'socket-closed', 'unavailable-id', 'webrtc'];
this.peer.on('error', (e) => {
        if (FATAL_ERRORS.includes(e.type)) {
          this.reconnectTimeout(e); // this function waits then tries the entire connection over again
        } else {
          console.log('Non fatal error: ',  e.type);
        }
      });

그리고 μ—°κ²° (제 κ²½μš°μ—λŠ” mediaConnection)에 λŒ€ν•΄ 이것을 가지고 μžˆμŠ΅λ‹ˆλ‹€.

call.on('error', (e) => {
      console.warn('error with stream', e);
      if (initiator) { // initiator is a value I set myself
        // Optionally this should call only the user that failed instead of the whole thing
        this.reconnectTimeout();
      }
    });

그리고 μ•žμ„œ μ–ΈκΈ‰ ν•œ reconnectTimeout λŠ” 전체 연결을 λ‹€μ‹œ μ‹œλ„ν•˜λŠ” κ°„λ‹¨ν•œ ν•¨μˆ˜μž…λ‹ˆλ‹€.

이둠적으둜이 λΌμ΄λΈŒλŸ¬λ¦¬λŠ” iceRestarts 처리 ν•  수 β€‹β€‹μžˆμœΌλ©° μ•„μ΄μŠ€ λ””μŠ€ 컀λ„₯νŠΈμ—μ„œ 치λͺ…적이지 μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. 이것은 λŒ€λΆ€λΆ„μ˜ 문제λ₯Ό ν•΄κ²°ν•  것이라고 λ―ΏμŠ΅λ‹ˆλ‹€. μ—°κ²° ν•΄μ œμ— λŒ€ν•œ PR이 μžˆμ§€λ§Œ 아직 λ‹€μ‹œ μ‹œμž‘ν•˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€.

μ„ μƒλ‹˜ μ €λŠ” μ—¬κΈ° 전체 ν”„λ‘œμ νŠΈμ— peer.jsλ₯Ό μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.
https://github.com/peers/peerjs/blob/master/dist/peerjs.js

이제 두 ν”Όμ–΄κ°€ 화상 톡화λ₯Ό μœ„ν•΄ μ„œλ‘œ μ—°κ²°ν–ˆμ„ λ•Œ λ¬Έμ œκ°€ λ°œμƒν•˜κ³ , ν•œ ν”Όμ–΄κ°€ 느린 연결을 얻을 λ•Œ iceconnection 두 ν”Όμ–΄ 연결을 λŠμŠ΅λ‹ˆλ‹€.

그리고 이것은 두 ν”Όμ–΄μ˜ 연결을 λŠλŠ” peerjs 파일의 μ½”λ“œμž…λ‹ˆλ‹€.

```
peerConnection.oniceconnectionstatechange = function () {
μŠ€μœ„μΉ˜ (peerConnection.iceConnectionState) {
사둀 "μ‹€νŒ¨":
logger_1.default.log ( "iceConnectionStateκ°€ μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€."+ peerId에 λŒ€ν•œ 연결을 λ‹«μŠ΅λ‹ˆλ‹€);

      _this.connection.emit(enums_1.ConnectionEventType.Error, new Error("Negotiation of connection to " + peerId + " failed."));

      _this.connection.close();

      break;

    case "closed":
      logger_1.default.log("iceConnectionState is closed, closing connections to " + peerId);

      _this.connection.emit(enums_1.ConnectionEventType.Error, new Error("Connection to " + peerId + " closed."));

      _this.connection.close();

      break;

    case "disconnected":
      logger_1.default.log("iceConnectionState is disconnected, closing connections to " + peerId);

      _this.connection.emit(enums_1.ConnectionEventType.Error, new Error("Connection to " + peerId + " disconnected."));

      _this.connection.close();

      break;

    case "completed":
      peerConnection.onicecandidate = util_1.util.noop;
      break;
  }

  _this.connection.emit(enums_1.ConnectionEventType.IceStateChanged, peerConnection.iceConnectionState);
}; // DATACONNECTION.
please check this code 

μΌ€μ΄μŠ€ "μ—°κ²° λŠκΉ€":
logger_1.default.log ( "iceConnectionStateκ°€ μ—°κ²° ν•΄μ œλ˜μ–΄"+ peerId에 λŒ€ν•œ 연결이 λ‹«νž˜);

      _this.connection.emit(enums_1.ConnectionEventType.Error, new Error("Connection to " + peerId + " disconnected."));

      **_this.connection.close();**

```

μ—¬κΈ° 연결이 κ°€κΉŒμ›Œμ§€κ³  여기에 μ–ΌμŒ 연결을 λ‹€μ‹œ μ—°κ²°ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€

λ‚΄ λ‹΅μž₯을 λ‹€μ‹œ μ½μœΌμ‹­μ‹œμ˜€. λ‚˜λŠ” λ‚΄κ°€ μ•„λŠ” ν•œ λͺ…ν™•ν•˜κ²Œ μ„€λͺ…ν–ˆλ‹€.

이 λΌμ΄λΈŒλŸ¬λ¦¬λŠ” 연결을 μ¦‰μ‹œ λ‹«κΈ° λ•Œλ¬Έμ— 연결이 끊긴 μƒνƒœμ˜ 정상 볡ꡬλ₯Ό μˆ˜ν–‰ ν•  수 μ—†μŠ΅λ‹ˆλ‹€. ν•  μˆ˜μžˆλŠ” μœ μΌν•œ 방법은 on ( 'error')을 λ“£κ³  μ›λž˜ 연결을 μ„€μ •ν•  λ•Œμ™€ λ˜‘κ°™μ€ λ°©μ‹μœΌλ‘œ μ—°κ²°ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. κ½€ 고톡 μŠ€λŸ½μŠ΅λ‹ˆλ‹€.

μœ μΌν•œ λ‹€λ₯Έ μ˜΅μ…˜μ€ ν¬ν¬ν•˜κ±°λ‚˜ μ—¬κΈ°μ—μ„œ λ‚΄ 포크λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€ : https://github.com/peers/peerjs/pull/655

λ‹€λ₯Έ μ˜΅μ…˜μ΄ μžˆμŠ΅λ‹ˆκΉŒ? λ˜λŠ” ν”Όμ–΄ jsμ—μ„œ λ‚˜λ₯Ό λ„μšΈ 수 μžˆλ‹€λ©΄ μ–΄λ””μ—μ„œ μ–΄λ–€ μ½”λ“œλ₯Ό μž‘μ„±ν•΄μ•Όν•©λ‹ˆκΉŒ?
정말 꼼짝 λͺ»ν–ˆμ–΄μš” ....

@jrowny 쑰사해 μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€. 1.3.0μ—μ„œ λ°°μ†‘ν•˜κ² μŠ΅λ‹ˆλ‹€.

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰