Merge pull request #43 from mbattista/add-turn-server
allow to add password protected turn server
This commit is contained in:
commit
4589f758c6
12
README.md
12
README.md
@ -41,6 +41,7 @@ For n.eko room management software visit https://github.com/m1k1o/neko-rooms.
|
|||||||
- Added `?usr=<display-name>` that will prefill username. This allows creating auto-join links.
|
- Added `?usr=<display-name>` that will prefill username. This allows creating auto-join links.
|
||||||
- Added `?cast=1` that will hide all control and show only video.
|
- Added `?cast=1` that will hide all control and show only video.
|
||||||
- Shake keyboard icon if someone attempted to control when is nobody hosting.
|
- Shake keyboard icon if someone attempted to control when is nobody hosting.
|
||||||
|
- Support for password protected `NEKO_ICESERVERS` (by @mbattista).
|
||||||
|
|
||||||
### Bugs
|
### Bugs
|
||||||
- Fixed minor gst pipeline bug.
|
- Fixed minor gst pipeline bug.
|
||||||
@ -280,7 +281,16 @@ NEKO_CERT:
|
|||||||
NEKO_KEY:
|
NEKO_KEY:
|
||||||
- Path to the SSL-Certificate private key
|
- Path to the SSL-Certificate private key
|
||||||
- e.g. '/certs/key.pem'
|
- e.g. '/certs/key.pem'
|
||||||
|
NEKO_ICELITE:
|
||||||
|
- Use the ice lite protocol
|
||||||
|
- e.g. false
|
||||||
|
NEKO_ICESERVER:
|
||||||
|
- Describes a single STUN and TURN server that can be used by the ICEAgent to establish a connection with a peer (simple usage for server without authentication)
|
||||||
|
- e.g. 'stun:stun.l.google.com:19302'
|
||||||
|
NEKO_ICESERVERS:
|
||||||
|
- Describes multiple STUN and TURN server that can be used by the ICEAgent to establish a connection with a peer
|
||||||
|
- e.g. '[{"urls": ["turn:turn.example.com:19302", "stun:stun.example.com:19302"], "username": "name", "credential": "password"}, {"urls": ["stun:stun.example2.com:19302"]}]'
|
||||||
|
- [More information](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceServer)
|
||||||
```
|
```
|
||||||
|
|
||||||
# How to contribute?
|
# How to contribute?
|
||||||
|
@ -183,7 +183,7 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
|||||||
this._ws!.send(JSON.stringify({ event, ...payload }))
|
this._ws!.send(JSON.stringify({ event, ...payload }))
|
||||||
}
|
}
|
||||||
|
|
||||||
public createPeer(sdp: string, lite: boolean, servers: string[]) {
|
public createPeer(sdp: string, lite: boolean, servers: RTCIceServer[]) {
|
||||||
this.emit('debug', `creating peer`)
|
this.emit('debug', `creating peer`)
|
||||||
if (!this.socketOpen) {
|
if (!this.socketOpen) {
|
||||||
this.emit(
|
this.emit(
|
||||||
@ -202,7 +202,7 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
|||||||
this._peer = new RTCPeerConnection()
|
this._peer = new RTCPeerConnection()
|
||||||
if (lite !== true) {
|
if (lite !== true) {
|
||||||
this._peer = new RTCPeerConnection({
|
this._peer = new RTCPeerConnection({
|
||||||
iceServers: [{ urls: servers }],
|
iceServers: servers,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ export interface SignalProvideMessage extends WebSocketMessage, SignalProvidePay
|
|||||||
export interface SignalProvidePayload {
|
export interface SignalProvidePayload {
|
||||||
id: string
|
id: string
|
||||||
lite: boolean
|
lite: boolean
|
||||||
ice: string[]
|
ice: RTCIceServer[]
|
||||||
sdp: string
|
sdp: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,10 +39,10 @@ import (
|
|||||||
|
|
||||||
// Pipeline is a wrapper for a GStreamer Pipeline
|
// Pipeline is a wrapper for a GStreamer Pipeline
|
||||||
type Pipeline struct {
|
type Pipeline struct {
|
||||||
Pipeline *C.GstElement
|
Pipeline *C.GstElement
|
||||||
Sample chan types.Sample
|
Sample chan types.Sample
|
||||||
Src string
|
Src string
|
||||||
id int
|
id int
|
||||||
}
|
}
|
||||||
|
|
||||||
var pipelines = make(map[int]*Pipeline)
|
var pipelines = make(map[int]*Pipeline)
|
||||||
@ -209,10 +209,10 @@ func CreatePipeline(pipelineStr string) (*Pipeline, error) {
|
|||||||
defer pipelinesLock.Unlock()
|
defer pipelinesLock.Unlock()
|
||||||
|
|
||||||
p := &Pipeline{
|
p := &Pipeline{
|
||||||
Pipeline: C.gstreamer_send_create_pipeline(pipelineStrUnsafe),
|
Pipeline: C.gstreamer_send_create_pipeline(pipelineStrUnsafe),
|
||||||
Sample: make(chan types.Sample),
|
Sample: make(chan types.Sample),
|
||||||
Src: pipelineStr,
|
Src: pipelineStr,
|
||||||
id: len(pipelines),
|
id: len(pipelines),
|
||||||
}
|
}
|
||||||
|
|
||||||
pipelines[p.id] = p
|
pipelines[p.id] = p
|
||||||
|
@ -1,102 +1,102 @@
|
|||||||
package endpoint
|
package endpoint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
|
||||||
"github.com/go-chi/chi/middleware"
|
"github.com/go-chi/chi/middleware"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Endpoint func(http.ResponseWriter, *http.Request) error
|
Endpoint func(http.ResponseWriter, *http.Request) error
|
||||||
|
|
||||||
ErrResponse struct {
|
ErrResponse struct {
|
||||||
Status int `json:"status,omitempty"`
|
Status int `json:"status,omitempty"`
|
||||||
Err string `json:"error,omitempty"`
|
Err string `json:"error,omitempty"`
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
Details string `json:"details,omitempty"`
|
Details string `json:"details,omitempty"`
|
||||||
Code string `json:"code,omitempty"`
|
Code string `json:"code,omitempty"`
|
||||||
RequestID string `json:"request,omitempty"`
|
RequestID string `json:"request,omitempty"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func Handle(handler Endpoint) http.HandlerFunc {
|
func Handle(handler Endpoint) http.HandlerFunc {
|
||||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||||
if err := handler(w, r); err != nil {
|
if err := handler(w, r); err != nil {
|
||||||
WriteError(w, r, err)
|
WriteError(w, r, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(fn)
|
return http.HandlerFunc(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
var nonErrorsCodes = map[int]bool{
|
var nonErrorsCodes = map[int]bool{
|
||||||
404: true,
|
404: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
func errResponse(input interface{}) *ErrResponse {
|
func errResponse(input interface{}) *ErrResponse {
|
||||||
var res *ErrResponse
|
var res *ErrResponse
|
||||||
var err interface{}
|
var err interface{}
|
||||||
|
|
||||||
switch input.(type) {
|
switch input.(type) {
|
||||||
case *HandlerError:
|
case *HandlerError:
|
||||||
e := input.(*HandlerError)
|
e := input.(*HandlerError)
|
||||||
res = &ErrResponse{
|
res = &ErrResponse{
|
||||||
Status: e.Status,
|
Status: e.Status,
|
||||||
Err: http.StatusText(e.Status),
|
Err: http.StatusText(e.Status),
|
||||||
Message: e.Message,
|
Message: e.Message,
|
||||||
}
|
}
|
||||||
err = e.Err
|
err = e.Err
|
||||||
default:
|
default:
|
||||||
res = &ErrResponse{
|
res = &ErrResponse{
|
||||||
Status: http.StatusInternalServerError,
|
Status: http.StatusInternalServerError,
|
||||||
Err: http.StatusText(http.StatusInternalServerError),
|
Err: http.StatusText(http.StatusInternalServerError),
|
||||||
}
|
}
|
||||||
err = input
|
err = input
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case *error:
|
case *error:
|
||||||
e := err.(error)
|
e := err.(error)
|
||||||
res.Details = e.Error()
|
res.Details = e.Error()
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
res.Details = fmt.Sprintf("%+v", err)
|
res.Details = fmt.Sprintf("%+v", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func WriteError(w http.ResponseWriter, r *http.Request, err interface{}) {
|
func WriteError(w http.ResponseWriter, r *http.Request, err interface{}) {
|
||||||
hlog := log.With().
|
hlog := log.With().
|
||||||
Str("module", "http").
|
Str("module", "http").
|
||||||
Logger()
|
Logger()
|
||||||
|
|
||||||
res := errResponse(err)
|
res := errResponse(err)
|
||||||
|
|
||||||
if reqID := middleware.GetReqID(r.Context()); reqID != "" {
|
if reqID := middleware.GetReqID(r.Context()); reqID != "" {
|
||||||
res.RequestID = reqID
|
res.RequestID = reqID
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(res.Status)
|
w.WriteHeader(res.Status)
|
||||||
|
|
||||||
if err := json.NewEncoder(w).Encode(res); err != nil {
|
if err := json.NewEncoder(w).Encode(res); err != nil {
|
||||||
hlog.Warn().Err(err).Msg("Failed writing json error response")
|
hlog.Warn().Err(err).Msg("Failed writing json error response")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !nonErrorsCodes[res.Status] {
|
if !nonErrorsCodes[res.Status] {
|
||||||
logEntry := middleware.GetLogEntry(r)
|
logEntry := middleware.GetLogEntry(r)
|
||||||
if logEntry != nil {
|
if logEntry != nil {
|
||||||
logEntry.Panic(err, debug.Stack())
|
logEntry.Panic(err, debug.Stack())
|
||||||
} else {
|
} else {
|
||||||
hlog.Error().Str("stack", string(debug.Stack())).Msgf("%+v", err)
|
hlog.Error().Str("stack", string(debug.Stack())).Msgf("%+v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,15 @@ package endpoint
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
type HandlerError struct {
|
type HandlerError struct {
|
||||||
Status int
|
Status int
|
||||||
Message string
|
Message string
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *HandlerError) Error() string {
|
func (e *HandlerError) Error() string {
|
||||||
if e.Err != nil {
|
if e.Err != nil {
|
||||||
return fmt.Sprintf("%s: %s", e.Message, e.Err.Error())
|
return fmt.Sprintf("%s: %s", e.Message, e.Err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.Message
|
return e.Message
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ package middleware
|
|||||||
// a pointer so it fits in an interface{} without allocation. This technique
|
// a pointer so it fits in an interface{} without allocation. This technique
|
||||||
// for defining context keys was copied from Go 1.7's new use of context in net/http.
|
// for defining context keys was copied from Go 1.7's new use of context in net/http.
|
||||||
type ctxKey struct {
|
type ctxKey struct {
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *ctxKey) String() string {
|
func (k *ctxKey) String() string {
|
||||||
return "neko/ctx/" + k.name
|
return "neko/ctx/" + k.name
|
||||||
}
|
}
|
||||||
|
@ -4,21 +4,21 @@ package middleware
|
|||||||
// https://github.com/zenazn/goji/tree/master/web/middleware
|
// https://github.com/zenazn/goji/tree/master/web/middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"n.eko.moe/neko/internal/http/endpoint"
|
"n.eko.moe/neko/internal/http/endpoint"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Recoverer(next http.Handler) http.Handler {
|
func Recoverer(next http.Handler) http.Handler {
|
||||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if rvr := recover(); rvr != nil {
|
if rvr := recover(); rvr != nil {
|
||||||
endpoint.WriteError(w, r, rvr)
|
endpoint.WriteError(w, r, rvr)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(fn)
|
return http.HandlerFunc(fn)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Key to use when setting the request ID.
|
// Key to use when setting the request ID.
|
||||||
@ -37,19 +37,19 @@ var reqid uint64
|
|||||||
// than a millionth of a percent chance of generating two colliding IDs.
|
// than a millionth of a percent chance of generating two colliding IDs.
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
hostname, err := os.Hostname()
|
hostname, err := os.Hostname()
|
||||||
if hostname == "" || err != nil {
|
if hostname == "" || err != nil {
|
||||||
hostname = "localhost"
|
hostname = "localhost"
|
||||||
}
|
}
|
||||||
var buf [12]byte
|
var buf [12]byte
|
||||||
var b64 string
|
var b64 string
|
||||||
for len(b64) < 10 {
|
for len(b64) < 10 {
|
||||||
rand.Read(buf[:])
|
rand.Read(buf[:])
|
||||||
b64 = base64.StdEncoding.EncodeToString(buf[:])
|
b64 = base64.StdEncoding.EncodeToString(buf[:])
|
||||||
b64 = strings.NewReplacer("+", "", "/", "").Replace(b64)
|
b64 = strings.NewReplacer("+", "", "/", "").Replace(b64)
|
||||||
}
|
}
|
||||||
|
|
||||||
prefix = fmt.Sprintf("%s/%s", hostname, b64[0:10])
|
prefix = fmt.Sprintf("%s/%s", hostname, b64[0:10])
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestID is a middleware that injects a request ID into the context of each
|
// RequestID is a middleware that injects a request ID into the context of each
|
||||||
@ -58,32 +58,32 @@ func init() {
|
|||||||
// process, and where the last number is an atomically incremented request
|
// process, and where the last number is an atomically incremented request
|
||||||
// counter.
|
// counter.
|
||||||
func RequestID(next http.Handler) http.Handler {
|
func RequestID(next http.Handler) http.Handler {
|
||||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
requestID := r.Header.Get("X-Request-Id")
|
requestID := r.Header.Get("X-Request-Id")
|
||||||
if requestID == "" {
|
if requestID == "" {
|
||||||
myid := atomic.AddUint64(&reqid, 1)
|
myid := atomic.AddUint64(&reqid, 1)
|
||||||
requestID = fmt.Sprintf("%s-%06d", prefix, myid)
|
requestID = fmt.Sprintf("%s-%06d", prefix, myid)
|
||||||
}
|
}
|
||||||
ctx = context.WithValue(ctx, RequestIDKey, requestID)
|
ctx = context.WithValue(ctx, RequestIDKey, requestID)
|
||||||
next.ServeHTTP(w, r.WithContext(ctx))
|
next.ServeHTTP(w, r.WithContext(ctx))
|
||||||
}
|
}
|
||||||
return http.HandlerFunc(fn)
|
return http.HandlerFunc(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReqID returns a request ID from the given context if one is present.
|
// GetReqID returns a request ID from the given context if one is present.
|
||||||
// Returns the empty string if a request ID cannot be found.
|
// Returns the empty string if a request ID cannot be found.
|
||||||
func GetReqID(ctx context.Context) string {
|
func GetReqID(ctx context.Context) string {
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if reqID, ok := ctx.Value(RequestIDKey).(string); ok {
|
if reqID, ok := ctx.Value(RequestIDKey).(string); ok {
|
||||||
return reqID
|
return reqID
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextRequestID generates the next request ID in the sequence.
|
// NextRequestID generates the next request ID in the sequence.
|
||||||
func NextRequestID() uint64 {
|
func NextRequestID() uint64 {
|
||||||
return atomic.AddUint64(&reqid, 1)
|
return atomic.AddUint64(&reqid, 1)
|
||||||
}
|
}
|
||||||
|
@ -126,8 +126,8 @@ func (session *Session) SignalCandidate(data string) error {
|
|||||||
}
|
}
|
||||||
return session.socket.Send(&message.SignalCandidate{
|
return session.socket.Send(&message.SignalCandidate{
|
||||||
Event: event.SIGNAL_CANDIDATE,
|
Event: event.SIGNAL_CANDIDATE,
|
||||||
Data: data,
|
Data: data,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *Session) destroy() error {
|
func (session *Session) destroy() error {
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"n.eko.moe/neko/internal/utils"
|
"n.eko.moe/neko/internal/utils"
|
||||||
|
|
||||||
|
"github.com/pion/webrtc/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebRTC struct {
|
type WebRTC struct {
|
||||||
ICELite bool
|
ICELite bool
|
||||||
ICEServers []string
|
ICEServers []webrtc.ICEServer
|
||||||
EphemeralMin uint16
|
EphemeralMin uint16
|
||||||
EphemeralMax uint16
|
EphemeralMax uint16
|
||||||
NAT1To1IPs []string
|
NAT1To1IPs []string
|
||||||
@ -38,13 +41,31 @@ func (WebRTC) Init(cmd *cobra.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().String("iceservers", "", "describes a single STUN and TURN server that can be used by the ICEAgent to establish a connection with a peer")
|
||||||
|
if err := viper.BindPFlag("iceservers", cmd.PersistentFlags().Lookup("iceservers")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WebRTC) Set() {
|
func (s *WebRTC) Set() {
|
||||||
s.ICELite = viper.GetBool("icelite")
|
|
||||||
s.ICEServers = viper.GetStringSlice("iceserver")
|
|
||||||
s.NAT1To1IPs = viper.GetStringSlice("nat1to1")
|
s.NAT1To1IPs = viper.GetStringSlice("nat1to1")
|
||||||
|
s.ICELite = viper.GetBool("icelite")
|
||||||
|
s.ICEServers = []webrtc.ICEServer{}
|
||||||
|
|
||||||
|
iceServersJson := viper.GetString("iceservers")
|
||||||
|
if iceServersJson != "" {
|
||||||
|
err := json.Unmarshal([]byte(iceServersJson), &s.ICEServers)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iceServerSlice := viper.GetStringSlice("iceserver")
|
||||||
|
if len(iceServerSlice) > 0 {
|
||||||
|
s.ICEServers = append(s.ICEServers, webrtc.ICEServer{URLs: iceServerSlice})
|
||||||
|
}
|
||||||
|
|
||||||
if len(s.NAT1To1IPs) == 0 {
|
if len(s.NAT1To1IPs) == 0 {
|
||||||
ip, err := utils.GetIP()
|
ip, err := utils.GetIP()
|
||||||
|
@ -2,6 +2,8 @@ package message
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"n.eko.moe/neko/internal/types"
|
"n.eko.moe/neko/internal/types"
|
||||||
|
|
||||||
|
"github.com/pion/webrtc/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
@ -14,11 +16,11 @@ type Disconnect struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SignalProvide struct {
|
type SignalProvide struct {
|
||||||
Event string `json:"event"`
|
Event string `json:"event"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
SDP string `json:"sdp"`
|
SDP string `json:"sdp"`
|
||||||
Lite bool `json:"lite"`
|
Lite bool `json:"lite"`
|
||||||
ICE []string `json:"ice"`
|
ICE []webrtc.ICEServer `json:"ice"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SignalAnswer struct {
|
type SignalAnswer struct {
|
||||||
@ -28,8 +30,8 @@ type SignalAnswer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SignalCandidate struct {
|
type SignalCandidate struct {
|
||||||
Event string `json:"event"`
|
Event string `json:"event"`
|
||||||
Data string `json:"data"`
|
Data string `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MembersList struct {
|
type MembersList struct {
|
||||||
@ -123,6 +125,6 @@ type BroadcastStatus struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BroadcastCreate struct {
|
type BroadcastCreate struct {
|
||||||
Event string `json:"event"`
|
Event string `json:"event"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
}
|
}
|
||||||
|
@ -2,18 +2,20 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/pion/webrtc/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Sample struct {
|
type Sample struct {
|
||||||
Data []byte
|
Data []byte
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
Duration time.Duration
|
Duration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebRTCManager interface {
|
type WebRTCManager interface {
|
||||||
Start()
|
Start()
|
||||||
Shutdown() error
|
Shutdown() error
|
||||||
CreatePeer(id string, session Session) (string, bool, []string, error)
|
CreatePeer(id string, session Session) (string, bool, []webrtc.ICEServer, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Peer interface {
|
type Peer interface {
|
||||||
|
@ -63,7 +63,7 @@ func (manager *WebRTCManager) Start() {
|
|||||||
|
|
||||||
manager.logger.Info().
|
manager.logger.Info().
|
||||||
Str("ice_lite", fmt.Sprintf("%t", manager.config.ICELite)).
|
Str("ice_lite", fmt.Sprintf("%t", manager.config.ICELite)).
|
||||||
Str("ice_servers", strings.Join(manager.config.ICEServers, ",")).
|
Str("ice_servers", fmt.Sprintf("%+v", manager.config.ICEServers)).
|
||||||
Str("ephemeral_port_range", fmt.Sprintf("%d-%d", manager.config.EphemeralMin, manager.config.EphemeralMax)).
|
Str("ephemeral_port_range", fmt.Sprintf("%d-%d", manager.config.EphemeralMin, manager.config.EphemeralMax)).
|
||||||
Str("nat_ips", strings.Join(manager.config.NAT1To1IPs, ",")).
|
Str("nat_ips", strings.Join(manager.config.NAT1To1IPs, ",")).
|
||||||
Msgf("webrtc starting")
|
Msgf("webrtc starting")
|
||||||
@ -74,13 +74,9 @@ func (manager *WebRTCManager) Shutdown() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (manager *WebRTCManager) CreatePeer(id string, session types.Session) (string, bool, []string, error) {
|
func (manager *WebRTCManager) CreatePeer(id string, session types.Session) (string, bool, []webrtc.ICEServer, error) {
|
||||||
configuration := &webrtc.Configuration{
|
configuration := &webrtc.Configuration{
|
||||||
ICEServers: []webrtc.ICEServer{
|
ICEServers: manager.config.ICEServers,
|
||||||
{
|
|
||||||
URLs: manager.config.ICEServers,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SDPSemantics: webrtc.SDPSemanticsUnifiedPlanWithFallback,
|
SDPSemantics: webrtc.SDPSemanticsUnifiedPlanWithFallback,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +95,7 @@ func (manager *WebRTCManager) CreatePeer(id string, session types.Session) (stri
|
|||||||
|
|
||||||
settings.SetEphemeralUDPPortRange(manager.config.EphemeralMin, manager.config.EphemeralMax)
|
settings.SetEphemeralUDPPortRange(manager.config.EphemeralMin, manager.config.EphemeralMax)
|
||||||
settings.SetNAT1To1IPs(manager.config.NAT1To1IPs, webrtc.ICECandidateTypeHost)
|
settings.SetNAT1To1IPs(manager.config.NAT1To1IPs, webrtc.ICECandidateTypeHost)
|
||||||
settings.SetICETimeouts(6 * time.Second, 6 * time.Second, 3 * time.Second)
|
settings.SetICETimeouts(6*time.Second, 6*time.Second, 3*time.Second)
|
||||||
settings.SetSRTPReplayProtectionWindow(512)
|
settings.SetSRTPReplayProtectionWindow(512)
|
||||||
|
|
||||||
// Create MediaEngine based off sdp
|
// Create MediaEngine based off sdp
|
||||||
@ -146,12 +142,12 @@ func (manager *WebRTCManager) CreatePeer(id string, session types.Session) (stri
|
|||||||
Msg("connection state has changed")
|
Msg("connection state has changed")
|
||||||
})
|
})
|
||||||
|
|
||||||
rtpVideo, err := connection.AddTrack(manager.videoTrack);
|
rtpVideo, err := connection.AddTrack(manager.videoTrack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", manager.config.ICELite, manager.config.ICEServers, err
|
return "", manager.config.ICELite, manager.config.ICEServers, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rtpAudio, err := connection.AddTrack(manager.audioTrack);
|
rtpAudio, err := connection.AddTrack(manager.audioTrack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", manager.config.ICELite, manager.config.ICEServers, err
|
return "", manager.config.ICELite, manager.config.ICEServers, err
|
||||||
}
|
}
|
||||||
@ -234,7 +230,6 @@ func (manager *WebRTCManager) CreatePeer(id string, session types.Session) (stri
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
||||||
return description.SDP, manager.config.ICELite, manager.config.ICEServers, nil
|
return description.SDP, manager.config.ICELite, manager.config.ICEServers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,6 @@ func (h *MessageHandler) Message(id string, raw []byte) error {
|
|||||||
return h.controlKeyboard(id, session, payload)
|
return h.controlKeyboard(id, session, payload)
|
||||||
}), "%s failed", header.Event)
|
}), "%s failed", header.Event)
|
||||||
|
|
||||||
|
|
||||||
// Chat Events
|
// Chat Events
|
||||||
case event.CHAT_MESSAGE:
|
case event.CHAT_MESSAGE:
|
||||||
payload := &message.ChatReceive{}
|
payload := &message.ChatReceive{}
|
||||||
|
@ -21,11 +21,11 @@ func New(sessions types.SessionManager, remote types.RemoteManager, broadcast ty
|
|||||||
logger := log.With().Str("module", "websocket").Logger()
|
logger := log.With().Str("module", "websocket").Logger()
|
||||||
|
|
||||||
return &WebSocketHandler{
|
return &WebSocketHandler{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
conf: conf,
|
conf: conf,
|
||||||
sessions: sessions,
|
sessions: sessions,
|
||||||
remote: remote,
|
remote: remote,
|
||||||
upgrader: websocket.Upgrader{
|
upgrader: websocket.Upgrader{
|
||||||
CheckOrigin: func(r *http.Request) bool {
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
@ -47,14 +47,14 @@ func New(sessions types.SessionManager, remote types.RemoteManager, broadcast ty
|
|||||||
const pingPeriod = 60 * time.Second
|
const pingPeriod = 60 * time.Second
|
||||||
|
|
||||||
type WebSocketHandler struct {
|
type WebSocketHandler struct {
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
upgrader websocket.Upgrader
|
upgrader websocket.Upgrader
|
||||||
sessions types.SessionManager
|
sessions types.SessionManager
|
||||||
remote types.RemoteManager
|
remote types.RemoteManager
|
||||||
conf *config.WebSocket
|
conf *config.WebSocket
|
||||||
handler *MessageHandler
|
handler *MessageHandler
|
||||||
conns uint32
|
conns uint32
|
||||||
shutdown chan bool
|
shutdown chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *WebSocketHandler) Start() error {
|
func (ws *WebSocketHandler) Start() error {
|
||||||
|
@ -10,10 +10,10 @@ import "C"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"n.eko.moe/neko/internal/types"
|
"n.eko.moe/neko/internal/types"
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user