mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
format Go source code.
This commit is contained in:
parent
732764991b
commit
45679f1b86
@ -5,8 +5,8 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"demodesk/neko"
|
"demodesk/neko"
|
||||||
"demodesk/neko/modules"
|
|
||||||
"demodesk/neko/internal/config"
|
"demodesk/neko/internal/config"
|
||||||
|
"demodesk/neko/modules"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -3,8 +3,8 @@ package members
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"demodesk/neko/internal/utils"
|
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
|
"demodesk/neko/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MemberDataPayload struct {
|
type MemberDataPayload struct {
|
||||||
@ -29,11 +29,11 @@ func (h *MembersHandler) membersCreate(w http.ResponseWriter, r *http.Request) {
|
|||||||
data := &MemberDataPayload{
|
data := &MemberDataPayload{
|
||||||
// default values
|
// default values
|
||||||
MemberProfile: &types.MemberProfile{
|
MemberProfile: &types.MemberProfile{
|
||||||
IsAdmin: false,
|
IsAdmin: false,
|
||||||
CanLogin: true,
|
CanLogin: true,
|
||||||
CanConnect: true,
|
CanConnect: true,
|
||||||
CanWatch: true,
|
CanWatch: true,
|
||||||
CanHost: true,
|
CanHost: true,
|
||||||
CanAccessClipboard: true,
|
CanAccessClipboard: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@ import (
|
|||||||
|
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
|
|
||||||
|
"demodesk/neko/internal/http/auth"
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/utils"
|
"demodesk/neko/internal/utils"
|
||||||
"demodesk/neko/internal/http/auth"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type key int
|
type key int
|
||||||
|
@ -3,14 +3,14 @@ package room
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"demodesk/neko/internal/utils"
|
|
||||||
"demodesk/neko/internal/types/event"
|
"demodesk/neko/internal/types/event"
|
||||||
"demodesk/neko/internal/types/message"
|
"demodesk/neko/internal/types/message"
|
||||||
|
"demodesk/neko/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BroadcastStatusPayload struct {
|
type BroadcastStatusPayload struct {
|
||||||
URL string `json:"url,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *RoomHandler) broadcastStatus(w http.ResponseWriter, r *http.Request) {
|
func (h *RoomHandler) broadcastStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -6,8 +6,8 @@ import (
|
|||||||
//"strings"
|
//"strings"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"demodesk/neko/internal/utils"
|
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
|
"demodesk/neko/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ClipboardPayload struct {
|
type ClipboardPayload struct {
|
||||||
|
@ -5,15 +5,15 @@ import (
|
|||||||
|
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
|
|
||||||
|
"demodesk/neko/internal/http/auth"
|
||||||
"demodesk/neko/internal/types/event"
|
"demodesk/neko/internal/types/event"
|
||||||
"demodesk/neko/internal/types/message"
|
"demodesk/neko/internal/types/message"
|
||||||
"demodesk/neko/internal/utils"
|
"demodesk/neko/internal/utils"
|
||||||
"demodesk/neko/internal/http/auth"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ControlStatusPayload struct {
|
type ControlStatusPayload struct {
|
||||||
HasHost bool `json:"has_host"`
|
HasHost bool `json:"has_host"`
|
||||||
HostId string `json:"host_id,omitempty"`
|
HostId string `json:"host_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ControlTargetPayload struct {
|
type ControlTargetPayload struct {
|
||||||
@ -30,7 +30,7 @@ func (h *RoomHandler) controlStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
} else {
|
} else {
|
||||||
utils.HttpSuccess(w, ControlStatusPayload{
|
utils.HttpSuccess(w, ControlStatusPayload{
|
||||||
HasHost: true,
|
HasHost: true,
|
||||||
HostId: host.ID(),
|
HostId: host.ID(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ import (
|
|||||||
|
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
|
|
||||||
"demodesk/neko/internal/types"
|
|
||||||
"demodesk/neko/internal/http/auth"
|
"demodesk/neko/internal/http/auth"
|
||||||
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/utils"
|
"demodesk/neko/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ package room
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"demodesk/neko/internal/utils"
|
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
|
"demodesk/neko/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type KeyboardMapData struct {
|
type KeyboardMapData struct {
|
||||||
@ -24,11 +24,11 @@ func (h *RoomHandler) keyboardMapSet(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := h.desktop.SetKeyboardMap(types.KeyboardMap{
|
err := h.desktop.SetKeyboardMap(types.KeyboardMap{
|
||||||
Layout: data.Layout,
|
Layout: data.Layout,
|
||||||
Variant: data.Variant,
|
Variant: data.Variant,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil{
|
if err != nil {
|
||||||
utils.HttpInternalServerError(w, "Unable to change keyboard map.")
|
utils.HttpInternalServerError(w, "Unable to change keyboard map.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -39,13 +39,13 @@ func (h *RoomHandler) keyboardMapSet(w http.ResponseWriter, r *http.Request) {
|
|||||||
func (h *RoomHandler) keyboardMapGet(w http.ResponseWriter, r *http.Request) {
|
func (h *RoomHandler) keyboardMapGet(w http.ResponseWriter, r *http.Request) {
|
||||||
data, err := h.desktop.GetKeyboardMap()
|
data, err := h.desktop.GetKeyboardMap()
|
||||||
|
|
||||||
if err != nil{
|
if err != nil {
|
||||||
utils.HttpInternalServerError(w, "Unable to get keyboard map.")
|
utils.HttpInternalServerError(w, "Unable to get keyboard map.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.HttpSuccess(w, KeyboardMapData{
|
utils.HttpSuccess(w, KeyboardMapData{
|
||||||
Layout: data.Layout,
|
Layout: data.Layout,
|
||||||
Variant: data.Variant,
|
Variant: data.Variant,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ func (h *RoomHandler) keyboardModifiersSet(w http.ResponseWriter, r *http.Reques
|
|||||||
}
|
}
|
||||||
|
|
||||||
h.desktop.SetKeyboardModifiers(types.KeyboardModifiers{
|
h.desktop.SetKeyboardModifiers(types.KeyboardModifiers{
|
||||||
NumLock: data.NumLock,
|
NumLock: data.NumLock,
|
||||||
CapsLock: data.CapsLock,
|
CapsLock: data.CapsLock,
|
||||||
})
|
})
|
||||||
utils.HttpSuccess(w)
|
utils.HttpSuccess(w)
|
||||||
@ -67,7 +67,7 @@ func (h *RoomHandler) keyboardModifiersGet(w http.ResponseWriter, r *http.Reques
|
|||||||
data := h.desktop.GetKeyboardModifiers()
|
data := h.desktop.GetKeyboardModifiers()
|
||||||
|
|
||||||
utils.HttpSuccess(w, KeyboardModifiersData{
|
utils.HttpSuccess(w, KeyboardModifiersData{
|
||||||
NumLock: data.NumLock,
|
NumLock: data.NumLock,
|
||||||
CapsLock: data.CapsLock,
|
CapsLock: data.CapsLock,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ package room
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
"strconv"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/types/event"
|
"demodesk/neko/internal/types/event"
|
||||||
@ -40,9 +40,9 @@ func (h *RoomHandler) screenConfigurationChange(w http.ResponseWriter, r *http.R
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := h.desktop.SetScreenSize(types.ScreenSize{
|
if err := h.desktop.SetScreenSize(types.ScreenSize{
|
||||||
Width: data.Width,
|
Width: data.Width,
|
||||||
Height: data.Height,
|
Height: data.Height,
|
||||||
Rate: data.Rate,
|
Rate: data.Rate,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
utils.HttpUnprocessableEntity(w, err)
|
utils.HttpUnprocessableEntity(w, err)
|
||||||
return
|
return
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package room
|
package room
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"demodesk/neko/internal/utils"
|
"demodesk/neko/internal/utils"
|
||||||
)
|
)
|
||||||
@ -62,7 +62,7 @@ func (h *RoomHandler) uploadDrop(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
defer srcFile.Close()
|
defer srcFile.Close()
|
||||||
|
|
||||||
dstFile, err := os.OpenFile(path, os.O_APPEND | os.O_CREATE | os.O_WRONLY, 0644)
|
dstFile, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.HttpInternalServerError(w, err)
|
utils.HttpInternalServerError(w, err)
|
||||||
return
|
return
|
||||||
@ -125,7 +125,7 @@ func (h *RoomHandler) uploadDialogPost(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
defer srcFile.Close()
|
defer srcFile.Close()
|
||||||
|
|
||||||
dstFile, err := os.OpenFile(path, os.O_APPEND | os.O_CREATE | os.O_WRONLY, 0644)
|
dstFile, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.HttpInternalServerError(w, err)
|
utils.HttpInternalServerError(w, err)
|
||||||
return
|
return
|
||||||
|
@ -7,10 +7,10 @@ import (
|
|||||||
|
|
||||||
"demodesk/neko/internal/api/members"
|
"demodesk/neko/internal/api/members"
|
||||||
"demodesk/neko/internal/api/room"
|
"demodesk/neko/internal/api/room"
|
||||||
|
"demodesk/neko/internal/config"
|
||||||
"demodesk/neko/internal/http/auth"
|
"demodesk/neko/internal/http/auth"
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/utils"
|
"demodesk/neko/internal/utils"
|
||||||
"demodesk/neko/internal/config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ApiManagerCtx struct {
|
type ApiManagerCtx struct {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"demodesk/neko/internal/utils"
|
|
||||||
"demodesk/neko/internal/types"
|
|
||||||
"demodesk/neko/internal/http/auth"
|
"demodesk/neko/internal/http/auth"
|
||||||
|
"demodesk/neko/internal/types"
|
||||||
|
"demodesk/neko/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SessionLoginPayload struct {
|
type SessionLoginPayload struct {
|
||||||
@ -33,16 +33,16 @@ func (api *ApiManagerCtx) Login(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: "neko-id",
|
Name: "neko-id",
|
||||||
Value: session.ID(),
|
Value: session.ID(),
|
||||||
Expires: time.Now().Add(365 * 24 * time.Hour),
|
Expires: time.Now().Add(365 * 24 * time.Hour),
|
||||||
HttpOnly: false,
|
HttpOnly: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: "neko-secret",
|
Name: "neko-secret",
|
||||||
Value: data.Secret,
|
Value: data.Secret,
|
||||||
Expires: time.Now().Add(365 * 24 * time.Hour),
|
Expires: time.Now().Add(365 * 24 * time.Hour),
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -55,16 +55,16 @@ func (api *ApiManagerCtx) Login(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func (api *ApiManagerCtx) Logout(w http.ResponseWriter, r *http.Request) {
|
func (api *ApiManagerCtx) Logout(w http.ResponseWriter, r *http.Request) {
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: "neko-id",
|
Name: "neko-id",
|
||||||
Value: "",
|
Value: "",
|
||||||
Expires: time.Unix(0, 0),
|
Expires: time.Unix(0, 0),
|
||||||
HttpOnly: false,
|
HttpOnly: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: "neko-secret",
|
Name: "neko-secret",
|
||||||
Value: "",
|
Value: "",
|
||||||
Expires: time.Unix(0, 0),
|
Expires: time.Unix(0, 0),
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@ package capture
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
@ -12,20 +12,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type BroacastManagerCtx struct {
|
type BroacastManagerCtx struct {
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
pipelineStr string
|
pipelineStr string
|
||||||
pipeline *gst.Pipeline
|
pipeline *gst.Pipeline
|
||||||
started bool
|
started bool
|
||||||
url string
|
url string
|
||||||
}
|
}
|
||||||
|
|
||||||
func broadcastNew(pipelineStr string) *BroacastManagerCtx {
|
func broadcastNew(pipelineStr string) *BroacastManagerCtx {
|
||||||
return &BroacastManagerCtx{
|
return &BroacastManagerCtx{
|
||||||
logger: log.With().Str("module", "capture").Str("submodule", "broadcast").Logger(),
|
logger: log.With().Str("module", "capture").Str("submodule", "broadcast").Logger(),
|
||||||
pipelineStr: pipelineStr,
|
pipelineStr: pipelineStr,
|
||||||
started: false,
|
started: false,
|
||||||
url: "",
|
url: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,18 +8,18 @@ package gst
|
|||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
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)
|
||||||
@ -45,14 +45,14 @@ func CreatePipeline(pipelineStr string) (*Pipeline, error) {
|
|||||||
|
|
||||||
if gstError != nil {
|
if gstError != nil {
|
||||||
defer C.g_error_free(gstError)
|
defer C.g_error_free(gstError)
|
||||||
return nil, fmt.Errorf("(pipeline error) %s", C.GoString(gstError.message))
|
return nil, fmt.Errorf("(pipeline error) %s", C.GoString(gstError.message))
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &Pipeline{
|
p := &Pipeline{
|
||||||
Pipeline: gstPipeline,
|
Pipeline: gstPipeline,
|
||||||
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
|
||||||
@ -96,7 +96,7 @@ func goHandlePipelineBuffer(buffer unsafe.Pointer, bufferLen C.int, duration C.i
|
|||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
pipeline.Sample <- types.Sample{
|
pipeline.Sample <- types.Sample{
|
||||||
Data: C.GoBytes(buffer, bufferLen),
|
Data: C.GoBytes(buffer, bufferLen),
|
||||||
Duration: time.Duration(duration),
|
Duration: time.Duration(duration),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -7,20 +7,20 @@ import (
|
|||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"demodesk/neko/internal/config"
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/types/codec"
|
"demodesk/neko/internal/types/codec"
|
||||||
"demodesk/neko/internal/config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CaptureManagerCtx struct {
|
type CaptureManagerCtx struct {
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
desktop types.DesktopManager
|
desktop types.DesktopManager
|
||||||
streaming bool
|
streaming bool
|
||||||
broadcast *BroacastManagerCtx
|
broadcast *BroacastManagerCtx
|
||||||
screencast *ScreencastManagerCtx
|
screencast *ScreencastManagerCtx
|
||||||
audio *StreamManagerCtx
|
audio *StreamManagerCtx
|
||||||
videos map[string]*StreamManagerCtx
|
videos map[string]*StreamManagerCtx
|
||||||
videoIDs []string
|
videoIDs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(desktop types.DesktopManager, config *config.Capture) *CaptureManagerCtx {
|
func New(desktop types.DesktopManager, config *config.Capture) *CaptureManagerCtx {
|
||||||
@ -29,124 +29,124 @@ func New(desktop types.DesktopManager, config *config.Capture) *CaptureManagerCt
|
|||||||
broadcastPipeline := config.BroadcastPipeline
|
broadcastPipeline := config.BroadcastPipeline
|
||||||
if broadcastPipeline == "" {
|
if broadcastPipeline == "" {
|
||||||
broadcastPipeline = fmt.Sprintf(
|
broadcastPipeline = fmt.Sprintf(
|
||||||
"flvmux name=mux ! rtmpsink location='{url} live=1' " +
|
"flvmux name=mux ! rtmpsink location='{url} live=1' "+
|
||||||
"pulsesrc device=%s " +
|
"pulsesrc device=%s "+
|
||||||
"! audio/x-raw,channels=2 " +
|
"! audio/x-raw,channels=2 "+
|
||||||
"! audioconvert " +
|
"! audioconvert "+
|
||||||
"! queue " +
|
"! queue "+
|
||||||
"! voaacenc " +
|
"! voaacenc "+
|
||||||
"! mux. " +
|
"! mux. "+
|
||||||
"ximagesrc display-name=%s show-pointer=true use-damage=false " +
|
"ximagesrc display-name=%s show-pointer=true use-damage=false "+
|
||||||
"! video/x-raw " +
|
"! video/x-raw "+
|
||||||
"! videoconvert " +
|
"! videoconvert "+
|
||||||
"! queue " +
|
"! queue "+
|
||||||
"! x264enc threads=4 bitrate=4096 key-int-max=15 byte-stream=true byte-stream=true tune=zerolatency speed-preset=veryfast " +
|
"! x264enc threads=4 bitrate=4096 key-int-max=15 byte-stream=true byte-stream=true tune=zerolatency speed-preset=veryfast "+
|
||||||
"! mux.", config.Device, config.Display,
|
"! mux.", config.Device, config.Display,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
screencastPipeline := config.ScreencastPipeline
|
screencastPipeline := config.ScreencastPipeline
|
||||||
if screencastPipeline == "" {
|
if screencastPipeline == "" {
|
||||||
screencastPipeline = fmt.Sprintf(
|
screencastPipeline = fmt.Sprintf(
|
||||||
"ximagesrc display-name=%s show-pointer=true use-damage=false " +
|
"ximagesrc display-name=%s show-pointer=true use-damage=false "+
|
||||||
"! video/x-raw,framerate=%s " +
|
"! video/x-raw,framerate=%s "+
|
||||||
"! videoconvert " +
|
"! videoconvert "+
|
||||||
"! queue " +
|
"! queue "+
|
||||||
"! jpegenc quality=%s " +
|
"! jpegenc quality=%s "+
|
||||||
"! appsink name=appsink", config.Display, config.ScreencastRate, config.ScreencastQuality,
|
"! appsink name=appsink", config.Display, config.ScreencastRate, config.ScreencastQuality,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &CaptureManagerCtx{
|
return &CaptureManagerCtx{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
desktop: desktop,
|
desktop: desktop,
|
||||||
streaming: false,
|
streaming: false,
|
||||||
broadcast: broadcastNew(broadcastPipeline),
|
broadcast: broadcastNew(broadcastPipeline),
|
||||||
screencast: screencastNew(config.Screencast, screencastPipeline),
|
screencast: screencastNew(config.Screencast, screencastPipeline),
|
||||||
audio: streamNew(config.AudioCodec, func() string {
|
audio: streamNew(config.AudioCodec, func() string {
|
||||||
if config.AudioPipeline != "" {
|
if config.AudioPipeline != "" {
|
||||||
return config.AudioPipeline
|
return config.AudioPipeline
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"pulsesrc device=%s " +
|
"pulsesrc device=%s "+
|
||||||
"! audio/x-raw,channels=2 " +
|
"! audio/x-raw,channels=2 "+
|
||||||
"! audioconvert " +
|
"! audioconvert "+
|
||||||
"! queue " +
|
"! queue "+
|
||||||
"! %s " +
|
"! %s "+
|
||||||
"! appsink name=appsink", config.Device, config.AudioCodec.Pipeline,
|
"! appsink name=appsink", config.Device, config.AudioCodec.Pipeline,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
videos: map[string]*StreamManagerCtx{
|
videos: map[string]*StreamManagerCtx{
|
||||||
"hd": streamNew(codec.VP8(), func() string {
|
"hd": streamNew(codec.VP8(), func() string {
|
||||||
screen := desktop.GetScreenSize()
|
screen := desktop.GetScreenSize()
|
||||||
bitrate := screen.Width * screen.Height * 12
|
bitrate := screen.Width * screen.Height * 12
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"ximagesrc display-name=%s show-pointer=false use-damage=false " +
|
"ximagesrc display-name=%s show-pointer=false use-damage=false "+
|
||||||
"! video/x-raw,framerate=25/1 " +
|
"! video/x-raw,framerate=25/1 "+
|
||||||
"! videoconvert " +
|
"! videoconvert "+
|
||||||
"! queue " +
|
"! queue "+
|
||||||
"! vp8enc target-bitrate=%d cpu-used=16 threads=4 deadline=100000 error-resilient=partitions keyframe-max-dist=15 auto-alt-ref=true min-quantizer=6 max-quantizer=12 " +
|
"! vp8enc target-bitrate=%d cpu-used=16 threads=4 deadline=100000 error-resilient=partitions keyframe-max-dist=15 auto-alt-ref=true min-quantizer=6 max-quantizer=12 "+
|
||||||
"! appsink name=appsink", config.Display, bitrate,
|
"! appsink name=appsink", config.Display, bitrate,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
"hq": streamNew(codec.VP8(), func() string {
|
"hq": streamNew(codec.VP8(), func() string {
|
||||||
screen := desktop.GetScreenSize()
|
screen := desktop.GetScreenSize()
|
||||||
width := int(math.Ceil(float64(screen.Width) / 6) * 5)
|
width := int(math.Ceil(float64(screen.Width)/6) * 5)
|
||||||
height := int(math.Ceil(float64(screen.Height) / 6) * 5)
|
height := int(math.Ceil(float64(screen.Height)/6) * 5)
|
||||||
bitrate := width * height * 12
|
bitrate := width * height * 12
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"ximagesrc display-name=%s show-pointer=false use-damage=false " +
|
"ximagesrc display-name=%s show-pointer=false use-damage=false "+
|
||||||
"! video/x-raw,framerate=25/1 " +
|
"! video/x-raw,framerate=25/1 "+
|
||||||
"! videoconvert " +
|
"! videoconvert "+
|
||||||
"! queue " +
|
"! queue "+
|
||||||
"! videoscale " +
|
"! videoscale "+
|
||||||
"! video/x-raw,width=%d,height=%d " +
|
"! video/x-raw,width=%d,height=%d "+
|
||||||
"! queue " +
|
"! queue "+
|
||||||
"! vp8enc target-bitrate=%d cpu-used=16 threads=4 deadline=100000 error-resilient=partitions keyframe-max-dist=15 auto-alt-ref=true min-quantizer=6 max-quantizer=12 " +
|
"! vp8enc target-bitrate=%d cpu-used=16 threads=4 deadline=100000 error-resilient=partitions keyframe-max-dist=15 auto-alt-ref=true min-quantizer=6 max-quantizer=12 "+
|
||||||
"! appsink name=appsink", config.Display, width, height, bitrate,
|
"! appsink name=appsink", config.Display, width, height, bitrate,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
"mq": streamNew(codec.VP8(), func() string {
|
"mq": streamNew(codec.VP8(), func() string {
|
||||||
screen := desktop.GetScreenSize()
|
screen := desktop.GetScreenSize()
|
||||||
width := int(math.Ceil(float64(screen.Width) / 6) * 4)
|
width := int(math.Ceil(float64(screen.Width)/6) * 4)
|
||||||
height := int(math.Ceil(float64(screen.Height) / 6) * 4)
|
height := int(math.Ceil(float64(screen.Height)/6) * 4)
|
||||||
bitrate := width * height * 8
|
bitrate := width * height * 8
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"ximagesrc display-name=%s show-pointer=false use-damage=false " +
|
"ximagesrc display-name=%s show-pointer=false use-damage=false "+
|
||||||
"! video/x-raw,framerate=125/10 " +
|
"! video/x-raw,framerate=125/10 "+
|
||||||
"! videoconvert " +
|
"! videoconvert "+
|
||||||
"! queue " +
|
"! queue "+
|
||||||
"! videoscale " +
|
"! videoscale "+
|
||||||
"! video/x-raw,width=%d,height=%d " +
|
"! video/x-raw,width=%d,height=%d "+
|
||||||
"! queue " +
|
"! queue "+
|
||||||
"! vp8enc target-bitrate=%d cpu-used=16 threads=4 deadline=100000 error-resilient=partitions keyframe-max-dist=15 auto-alt-ref=true min-quantizer=12 max-quantizer=24 " +
|
"! vp8enc target-bitrate=%d cpu-used=16 threads=4 deadline=100000 error-resilient=partitions keyframe-max-dist=15 auto-alt-ref=true min-quantizer=12 max-quantizer=24 "+
|
||||||
"! appsink name=appsink", config.Display, width, height, bitrate,
|
"! appsink name=appsink", config.Display, width, height, bitrate,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
"lq": streamNew(codec.VP8(), func() string {
|
"lq": streamNew(codec.VP8(), func() string {
|
||||||
screen := desktop.GetScreenSize()
|
screen := desktop.GetScreenSize()
|
||||||
width := int(math.Ceil(float64(screen.Width) / 6) * 3)
|
width := int(math.Ceil(float64(screen.Width)/6) * 3)
|
||||||
height := int(math.Ceil(float64(screen.Height) / 6) * 3)
|
height := int(math.Ceil(float64(screen.Height)/6) * 3)
|
||||||
bitrate := width * height * 4
|
bitrate := width * height * 4
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"ximagesrc display-name=%s show-pointer=false use-damage=false " +
|
"ximagesrc display-name=%s show-pointer=false use-damage=false "+
|
||||||
"! video/x-raw,framerate=125/10 " +
|
"! video/x-raw,framerate=125/10 "+
|
||||||
"! videoconvert " +
|
"! videoconvert "+
|
||||||
"! queue " +
|
"! queue "+
|
||||||
"! videoscale " +
|
"! videoscale "+
|
||||||
"! video/x-raw,width=%d,height=%d " +
|
"! video/x-raw,width=%d,height=%d "+
|
||||||
"! queue " +
|
"! queue "+
|
||||||
"! vp8enc target-bitrate=%d cpu-used=16 threads=4 deadline=100000 error-resilient=partitions keyframe-max-dist=15 auto-alt-ref=true min-quantizer=12 max-quantizer=24 " +
|
"! vp8enc target-bitrate=%d cpu-used=16 threads=4 deadline=100000 error-resilient=partitions keyframe-max-dist=15 auto-alt-ref=true min-quantizer=12 max-quantizer=24 "+
|
||||||
"! appsink name=appsink", config.Display, width, height, bitrate,
|
"! appsink name=appsink", config.Display, width, height, bitrate,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
videoIDs: []string{ "hd", "hq", "mq", "lq" },
|
videoIDs: []string{"hd", "hq", "mq", "lq"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,41 +2,41 @@ package capture
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"demodesk/neko/internal/types"
|
|
||||||
"demodesk/neko/internal/capture/gst"
|
"demodesk/neko/internal/capture/gst"
|
||||||
|
"demodesk/neko/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ScreencastManagerCtx struct {
|
type ScreencastManagerCtx struct {
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
pipelineStr string
|
pipelineStr string
|
||||||
pipeline *gst.Pipeline
|
pipeline *gst.Pipeline
|
||||||
enabled bool
|
enabled bool
|
||||||
started bool
|
started bool
|
||||||
emitStop chan bool
|
emitStop chan bool
|
||||||
emitUpdate chan bool
|
emitUpdate chan bool
|
||||||
expired int32
|
expired int32
|
||||||
sample chan types.Sample
|
sample chan types.Sample
|
||||||
image types.Sample
|
image types.Sample
|
||||||
}
|
}
|
||||||
|
|
||||||
const screencastTimeout = 5 * time.Second
|
const screencastTimeout = 5 * time.Second
|
||||||
|
|
||||||
func screencastNew(enabled bool, pipelineStr string) *ScreencastManagerCtx {
|
func screencastNew(enabled bool, pipelineStr string) *ScreencastManagerCtx {
|
||||||
manager := &ScreencastManagerCtx{
|
manager := &ScreencastManagerCtx{
|
||||||
logger: log.With().Str("module", "capture").Str("submodule", "screencast").Logger(),
|
logger: log.With().Str("module", "capture").Str("submodule", "screencast").Logger(),
|
||||||
pipelineStr: pipelineStr,
|
pipelineStr: pipelineStr,
|
||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
started: false,
|
started: false,
|
||||||
emitStop: make(chan bool),
|
emitStop: make(chan bool),
|
||||||
emitUpdate: make(chan bool),
|
emitUpdate: make(chan bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -146,7 +146,7 @@ func (manager *ScreencastManagerCtx) createPipeline() error {
|
|||||||
|
|
||||||
manager.pipeline.Start()
|
manager.pipeline.Start()
|
||||||
manager.sample = manager.pipeline.Sample
|
manager.sample = manager.pipeline.Sample
|
||||||
manager.emitUpdate <-true
|
manager.emitUpdate <- true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,40 +2,40 @@ package capture
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"demodesk/neko/internal/capture/gst"
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/types/codec"
|
"demodesk/neko/internal/types/codec"
|
||||||
"demodesk/neko/internal/capture/gst"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type StreamManagerCtx struct {
|
type StreamManagerCtx struct {
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
codec codec.RTPCodec
|
codec codec.RTPCodec
|
||||||
pipelineStr func() string
|
pipelineStr func() string
|
||||||
pipeline *gst.Pipeline
|
pipeline *gst.Pipeline
|
||||||
sample chan types.Sample
|
sample chan types.Sample
|
||||||
listeners map[uintptr]*func(sample types.Sample)
|
listeners map[uintptr]*func(sample types.Sample)
|
||||||
emitMu sync.Mutex
|
emitMu sync.Mutex
|
||||||
emitUpdate chan bool
|
emitUpdate chan bool
|
||||||
emitStop chan bool
|
emitStop chan bool
|
||||||
started bool
|
started bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func streamNew(codec codec.RTPCodec, pipelineStr func() string) *StreamManagerCtx {
|
func streamNew(codec codec.RTPCodec, pipelineStr func() string) *StreamManagerCtx {
|
||||||
manager := &StreamManagerCtx{
|
manager := &StreamManagerCtx{
|
||||||
logger: log.With().Str("module", "capture").Str("submodule", "stream").Logger(),
|
logger: log.With().Str("module", "capture").Str("submodule", "stream").Logger(),
|
||||||
codec: codec,
|
codec: codec,
|
||||||
pipelineStr: pipelineStr,
|
pipelineStr: pipelineStr,
|
||||||
listeners: map[uintptr]*func(sample types.Sample){},
|
listeners: map[uintptr]*func(sample types.Sample){},
|
||||||
emitUpdate: make(chan bool),
|
emitUpdate: make(chan bool),
|
||||||
emitStop: make(chan bool),
|
emitStop: make(chan bool),
|
||||||
started: false,
|
started: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -146,7 +146,7 @@ func (manager *StreamManagerCtx) createPipeline() error {
|
|||||||
manager.pipeline.Start()
|
manager.pipeline.Start()
|
||||||
|
|
||||||
manager.sample = manager.pipeline.Sample
|
manager.sample = manager.pipeline.Sample
|
||||||
manager.emitUpdate <-true
|
manager.emitUpdate <- true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,15 +8,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Capture struct {
|
type Capture struct {
|
||||||
Device string
|
Device string
|
||||||
AudioCodec codec.RTPCodec
|
AudioCodec codec.RTPCodec
|
||||||
AudioPipeline string
|
AudioPipeline string
|
||||||
|
|
||||||
Display string
|
Display string
|
||||||
//VideoCodec codec.RTPCodec
|
//VideoCodec codec.RTPCodec
|
||||||
//VideoPipeline string
|
//VideoPipeline string
|
||||||
|
|
||||||
BroadcastPipeline string
|
BroadcastPipeline string
|
||||||
|
|
||||||
Screencast bool
|
Screencast bool
|
||||||
ScreencastRate string
|
ScreencastRate string
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package desktop
|
package desktop
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ func (manager *DesktopManagerCtx) ClipboardSetBinary(mime string, data []byte) e
|
|||||||
var stderr bytes.Buffer
|
var stderr bytes.Buffer
|
||||||
cmd.Stderr = &stderr
|
cmd.Stderr = &stderr
|
||||||
|
|
||||||
stdin, err := cmd.StdinPipe()
|
stdin, err := cmd.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
DROP_MOVE_REPEAT = 4
|
DROP_MOVE_REPEAT = 4
|
||||||
DROP_DELAY = 100 * time.Millisecond
|
DROP_DELAY = 100 * time.Millisecond
|
||||||
)
|
)
|
||||||
|
|
||||||
func (manager *DesktopManagerCtx) DropFiles(x int, y int, files []string) bool {
|
func (manager *DesktopManagerCtx) DropFiles(x int, y int, files []string) bool {
|
||||||
@ -49,10 +49,10 @@ func (manager *DesktopManagerCtx) DropFiles(x int, y int, files []string) bool {
|
|||||||
go drop.OpenWindow(files)
|
go drop.OpenWindow(files)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case succeeded := <- finished:
|
case succeeded := <-finished:
|
||||||
return succeeded
|
return succeeded
|
||||||
case <-time.After(1 * time.Second):
|
case <-time.After(1 * time.Second):
|
||||||
drop.CloseWindow();
|
drop.CloseWindow()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ func OpenWindow(files []string) {
|
|||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
|
||||||
size := C.int(len(files))
|
size := C.int(len(files))
|
||||||
urisUnsafe := C.dragUrisMake(size);
|
urisUnsafe := C.dragUrisMake(size)
|
||||||
defer C.dragUrisFree(urisUnsafe, size)
|
defer C.dragUrisFree(urisUnsafe, size)
|
||||||
|
|
||||||
for i, file := range files {
|
for i, file := range files {
|
||||||
|
@ -2,8 +2,8 @@ package desktop
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -19,19 +19,19 @@ func (manager *DesktopManagerCtx) HandleFileChooserDialog(uri string) error {
|
|||||||
// TODO: Use native API.
|
// TODO: Use native API.
|
||||||
err1 := exec.Command(
|
err1 := exec.Command(
|
||||||
"xdotool",
|
"xdotool",
|
||||||
"search", "--name", FILE_CHOOSER_DIALOG_NAME, "windowfocus",
|
"search", "--name", FILE_CHOOSER_DIALOG_NAME, "windowfocus",
|
||||||
"sleep", FILE_CHOOSER_DIALOG_SHORT_SLEEP,
|
"sleep", FILE_CHOOSER_DIALOG_SHORT_SLEEP,
|
||||||
"key", "--clearmodifiers", "ctrl+l",
|
"key", "--clearmodifiers", "ctrl+l",
|
||||||
"type", "--args", "1", uri + "//",
|
"type", "--args", "1", uri+"//",
|
||||||
"sleep", FILE_CHOOSER_DIALOG_SHORT_SLEEP,
|
"sleep", FILE_CHOOSER_DIALOG_SHORT_SLEEP,
|
||||||
"key", "Delete", // remove autocomplete results
|
"key", "Delete", // remove autocomplete results
|
||||||
"sleep", FILE_CHOOSER_DIALOG_SHORT_SLEEP,
|
"sleep", FILE_CHOOSER_DIALOG_SHORT_SLEEP,
|
||||||
"key", "Return",
|
"key", "Return",
|
||||||
"sleep", FILE_CHOOSER_DIALOG_LONG_SLEEP,
|
"sleep", FILE_CHOOSER_DIALOG_LONG_SLEEP,
|
||||||
"key", "Down",
|
"key", "Down",
|
||||||
"key", "--clearmodifiers", "ctrl+a",
|
"key", "--clearmodifiers", "ctrl+a",
|
||||||
"key", "Return",
|
"key", "Return",
|
||||||
"sleep", FILE_CHOOSER_DIALOG_LONG_SLEEP,
|
"sleep", FILE_CHOOSER_DIALOG_LONG_SLEEP,
|
||||||
).Run()
|
).Run()
|
||||||
|
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
@ -41,7 +41,7 @@ func (manager *DesktopManagerCtx) HandleFileChooserDialog(uri string) error {
|
|||||||
// TODO: Use native API.
|
// TODO: Use native API.
|
||||||
err2 := exec.Command(
|
err2 := exec.Command(
|
||||||
"xdotool",
|
"xdotool",
|
||||||
"search", "--name", FILE_CHOOSER_DIALOG_NAME,
|
"search", "--name", FILE_CHOOSER_DIALOG_NAME,
|
||||||
).Run()
|
).Run()
|
||||||
|
|
||||||
// if last command didn't return error, consider dialog as still open
|
// if last command didn't return error, consider dialog as still open
|
||||||
@ -61,7 +61,7 @@ func (manager *DesktopManagerCtx) CloseFileChooserDialog() {
|
|||||||
// TODO: Use native API.
|
// TODO: Use native API.
|
||||||
err := exec.Command(
|
err := exec.Command(
|
||||||
"xdotool",
|
"xdotool",
|
||||||
"search", "--name", FILE_CHOOSER_DIALOG_NAME, "windowfocus",
|
"search", "--name", FILE_CHOOSER_DIALOG_NAME, "windowfocus",
|
||||||
).Run()
|
).Run()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -92,7 +92,7 @@ func (manager *DesktopManagerCtx) IsFileChooserDialogOpened() bool {
|
|||||||
// TODO: Use native API.
|
// TODO: Use native API.
|
||||||
err := exec.Command(
|
err := exec.Command(
|
||||||
"xdotool",
|
"xdotool",
|
||||||
"search", "--name", FILE_CHOOSER_DIALOG_NAME,
|
"search", "--name", FILE_CHOOSER_DIALOG_NAME,
|
||||||
).Run()
|
).Run()
|
||||||
|
|
||||||
return err == nil
|
return err == nil
|
||||||
|
@ -2,37 +2,37 @@ package desktop
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kataras/go-events"
|
"github.com/kataras/go-events"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"demodesk/neko/internal/config"
|
"demodesk/neko/internal/config"
|
||||||
"demodesk/neko/internal/desktop/xorg"
|
|
||||||
"demodesk/neko/internal/desktop/xevent"
|
"demodesk/neko/internal/desktop/xevent"
|
||||||
|
"demodesk/neko/internal/desktop/xorg"
|
||||||
)
|
)
|
||||||
|
|
||||||
var mu = sync.Mutex{}
|
var mu = sync.Mutex{}
|
||||||
|
|
||||||
type DesktopManagerCtx struct {
|
type DesktopManagerCtx struct {
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
cleanup *time.Ticker
|
cleanup *time.Ticker
|
||||||
shutdown chan bool
|
shutdown chan bool
|
||||||
emmiter events.EventEmmiter
|
emmiter events.EventEmmiter
|
||||||
display string
|
display string
|
||||||
config *config.Desktop
|
config *config.Desktop
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(display string, config *config.Desktop) *DesktopManagerCtx {
|
func New(display string, config *config.Desktop) *DesktopManagerCtx {
|
||||||
return &DesktopManagerCtx{
|
return &DesktopManagerCtx{
|
||||||
logger: log.With().Str("module", "desktop").Logger(),
|
logger: log.With().Str("module", "desktop").Logger(),
|
||||||
cleanup: time.NewTicker(1 * time.Second),
|
cleanup: time.NewTicker(1 * time.Second),
|
||||||
shutdown: make(chan bool),
|
shutdown: make(chan bool),
|
||||||
emmiter: events.New(),
|
emmiter: events.New(),
|
||||||
display: display,
|
display: display,
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,9 +8,9 @@ package xevent
|
|||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/kataras/go-events"
|
"github.com/kataras/go-events"
|
||||||
)
|
)
|
||||||
|
@ -2,11 +2,11 @@ package desktop
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
"regexp"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"demodesk/neko/internal/types"
|
|
||||||
"demodesk/neko/internal/desktop/xorg"
|
"demodesk/neko/internal/desktop/xorg"
|
||||||
|
"demodesk/neko/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Refactor.
|
// TODO: Refactor.
|
||||||
@ -119,7 +119,7 @@ func (manager *DesktopManagerCtx) GetKeyboardModifiers() types.KeyboardModifiers
|
|||||||
CapsLock := (modifiers & xorg.KBD_CAPS_LOCK) != 0
|
CapsLock := (modifiers & xorg.KBD_CAPS_LOCK) != 0
|
||||||
|
|
||||||
return types.KeyboardModifiers{
|
return types.KeyboardModifiers{
|
||||||
NumLock: &NumLock,
|
NumLock: &NumLock,
|
||||||
CapsLock: &CapsLock,
|
CapsLock: &CapsLock,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,13 +236,13 @@ func GetCursorImage() *types.CursorImage {
|
|||||||
height := uint16(cur.height)
|
height := uint16(cur.height)
|
||||||
|
|
||||||
return &types.CursorImage{
|
return &types.CursorImage{
|
||||||
Width: width,
|
Width: width,
|
||||||
Height: height,
|
Height: height,
|
||||||
Xhot: uint16(cur.xhot),
|
Xhot: uint16(cur.xhot),
|
||||||
Yhot: uint16(cur.yhot),
|
Yhot: uint16(cur.yhot),
|
||||||
Serial: uint64(cur.cursor_serial),
|
Serial: uint64(cur.cursor_serial),
|
||||||
// Xlib stores 32-bit data in longs, even if longs are 64-bits long.
|
// Xlib stores 32-bit data in longs, even if longs are 64-bits long.
|
||||||
Pixels: C.GoBytes(unsafe.Pointer(cur.pixels), C.int(width * height * 8)),
|
Pixels: C.GoBytes(unsafe.Pointer(cur.pixels), C.int(width*height*8)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ func GetScreenshotImage() *image.RGBA {
|
|||||||
|
|
||||||
var w, h C.int
|
var w, h C.int
|
||||||
pixelsUnsafe := C.XGetScreenshot(&w, &h)
|
pixelsUnsafe := C.XGetScreenshot(&w, &h)
|
||||||
pixels := C.GoBytes(unsafe.Pointer(pixelsUnsafe), w * h * 3)
|
pixels := C.GoBytes(unsafe.Pointer(pixelsUnsafe), w*h*3)
|
||||||
defer C.free(unsafe.Pointer(pixelsUnsafe))
|
defer C.free(unsafe.Pointer(pixelsUnsafe))
|
||||||
|
|
||||||
width := int(w)
|
width := int(w)
|
||||||
@ -288,7 +288,7 @@ func goSetScreenRates(index C.int, rate_index C.int, rateC C.short) {
|
|||||||
rate := int16(rateC)
|
rate := int16(rateC)
|
||||||
|
|
||||||
// filter out all irrelevant rates
|
// filter out all irrelevant rates
|
||||||
if rate > 60 || (rate > 30 && rate % 10 != 0){
|
if rate > 60 || (rate > 30 && rate%10 != 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ import (
|
|||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"demodesk/neko/internal/types"
|
|
||||||
"demodesk/neko/internal/config"
|
"demodesk/neko/internal/config"
|
||||||
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/utils"
|
"demodesk/neko/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ func New(WebSocketManager types.WebSocketManager, ApiManager types.ApiManager, c
|
|||||||
router := chi.NewRouter()
|
router := chi.NewRouter()
|
||||||
router.Use(middleware.Recoverer) // Recover from panics without crashing server
|
router.Use(middleware.Recoverer) // Recover from panics without crashing server
|
||||||
router.Use(cors.Handler(cors.Options{
|
router.Use(cors.Handler(cors.Options{
|
||||||
AllowOriginFunc: func(r *http.Request, origin string) bool {
|
AllowOriginFunc: func(r *http.Request, origin string) bool {
|
||||||
return conf.AllowOrigin(origin)
|
return conf.AllowOrigin(origin)
|
||||||
},
|
},
|
||||||
AllowedMethods: []string{"GET", "POST", "DELETE", "OPTIONS"},
|
AllowedMethods: []string{"GET", "POST", "DELETE", "OPTIONS"},
|
||||||
@ -39,7 +39,7 @@ func New(WebSocketManager types.WebSocketManager, ApiManager types.ApiManager, c
|
|||||||
MaxAge: 300, // Maximum value not ignored by any of major browsers
|
MaxAge: 300, // Maximum value not ignored by any of major browsers
|
||||||
}))
|
}))
|
||||||
router.Use(middleware.RequestID) // Create a request ID for each request
|
router.Use(middleware.RequestID) // Create a request ID for each request
|
||||||
router.Use(Logger) // Log API request calls using custom logger function
|
router.Use(Logger) // Log API request calls using custom logger function
|
||||||
|
|
||||||
router.Route("/api", ApiManager.Route)
|
router.Route("/api", ApiManager.Route)
|
||||||
|
|
||||||
|
@ -55,4 +55,4 @@ func getAuthData(r *http.Request) (string, string, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return "", "", false
|
return "", "", false
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ func New() types.MembersDatabase {
|
|||||||
return &MembersDatabaseCtx{}
|
return &MembersDatabaseCtx{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type MembersDatabaseCtx struct {}
|
type MembersDatabaseCtx struct{}
|
||||||
|
|
||||||
func (manager *MembersDatabaseCtx) Connect() error {
|
func (manager *MembersDatabaseCtx) Connect() error {
|
||||||
return nil
|
return nil
|
||||||
|
@ -2,9 +2,9 @@ package file
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"fmt"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"demodesk/neko/internal/config"
|
||||||
"demodesk/neko/internal/session/database/dummy"
|
"demodesk/neko/internal/session/database/dummy"
|
||||||
"demodesk/neko/internal/session/database/file"
|
"demodesk/neko/internal/session/database/file"
|
||||||
"demodesk/neko/internal/session/database/object"
|
"demodesk/neko/internal/session/database/object"
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(config *config.Session) types.MembersDatabase {
|
func New(config *config.Session) types.MembersDatabase {
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"demodesk/neko/internal/config"
|
||||||
"demodesk/neko/internal/session/database"
|
"demodesk/neko/internal/session/database"
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/config"
|
|
||||||
"demodesk/neko/internal/utils"
|
"demodesk/neko/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -72,25 +72,25 @@ func (manager *SessionManagerCtx) Connect() error {
|
|||||||
|
|
||||||
// create default admin account at startup
|
// create default admin account at startup
|
||||||
_ = manager.add("admin", types.MemberProfile{
|
_ = manager.add("admin", types.MemberProfile{
|
||||||
Secret: manager.config.AdminPassword,
|
Secret: manager.config.AdminPassword,
|
||||||
Name: "Administrator",
|
Name: "Administrator",
|
||||||
IsAdmin: true,
|
IsAdmin: true,
|
||||||
CanLogin: true,
|
CanLogin: true,
|
||||||
CanConnect: true,
|
CanConnect: true,
|
||||||
CanWatch: true,
|
CanWatch: true,
|
||||||
CanHost: true,
|
CanHost: true,
|
||||||
CanAccessClipboard: true,
|
CanAccessClipboard: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// create default user account at startup
|
// create default user account at startup
|
||||||
_ = manager.add("user", types.MemberProfile{
|
_ = manager.add("user", types.MemberProfile{
|
||||||
Secret: manager.config.Password,
|
Secret: manager.config.Password,
|
||||||
Name: "User",
|
Name: "User",
|
||||||
IsAdmin: false,
|
IsAdmin: false,
|
||||||
CanLogin: true,
|
CanLogin: true,
|
||||||
CanConnect: true,
|
CanConnect: true,
|
||||||
CanWatch: true,
|
CanWatch: true,
|
||||||
CanHost: true,
|
CanHost: true,
|
||||||
CanAccessClipboard: true,
|
CanAccessClipboard: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -19,14 +19,14 @@ func (codec *RTPCodec) Register(engine *webrtc.MediaEngine) error {
|
|||||||
|
|
||||||
func VP8() RTPCodec {
|
func VP8() RTPCodec {
|
||||||
return RTPCodec{
|
return RTPCodec{
|
||||||
Name: "vp8",
|
Name: "vp8",
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
Type: webrtc.RTPCodecTypeVideo,
|
Type: webrtc.RTPCodecTypeVideo,
|
||||||
Capability: webrtc.RTPCodecCapability{
|
Capability: webrtc.RTPCodecCapability{
|
||||||
MimeType: webrtc.MimeTypeVP8,
|
MimeType: webrtc.MimeTypeVP8,
|
||||||
ClockRate: 90000,
|
ClockRate: 90000,
|
||||||
Channels: 0,
|
Channels: 0,
|
||||||
SDPFmtpLine: "",
|
SDPFmtpLine: "",
|
||||||
RTCPFeedback: nil,
|
RTCPFeedback: nil,
|
||||||
},
|
},
|
||||||
// https://gstreamer.freedesktop.org/documentation/vpx/vp8enc.html
|
// https://gstreamer.freedesktop.org/documentation/vpx/vp8enc.html
|
||||||
@ -38,14 +38,14 @@ func VP8() RTPCodec {
|
|||||||
// TODO: Profile ID.
|
// TODO: Profile ID.
|
||||||
func VP9() RTPCodec {
|
func VP9() RTPCodec {
|
||||||
return RTPCodec{
|
return RTPCodec{
|
||||||
Name: "vp9",
|
Name: "vp9",
|
||||||
PayloadType: 98,
|
PayloadType: 98,
|
||||||
Type: webrtc.RTPCodecTypeVideo,
|
Type: webrtc.RTPCodecTypeVideo,
|
||||||
Capability: webrtc.RTPCodecCapability{
|
Capability: webrtc.RTPCodecCapability{
|
||||||
MimeType: webrtc.MimeTypeVP9,
|
MimeType: webrtc.MimeTypeVP9,
|
||||||
ClockRate: 90000,
|
ClockRate: 90000,
|
||||||
Channels: 0,
|
Channels: 0,
|
||||||
SDPFmtpLine: "profile-id=0",
|
SDPFmtpLine: "profile-id=0",
|
||||||
RTCPFeedback: nil,
|
RTCPFeedback: nil,
|
||||||
},
|
},
|
||||||
// https://gstreamer.freedesktop.org/documentation/vpx/vp9enc.html
|
// https://gstreamer.freedesktop.org/documentation/vpx/vp9enc.html
|
||||||
@ -57,14 +57,14 @@ func VP9() RTPCodec {
|
|||||||
// TODO: Profile ID.
|
// TODO: Profile ID.
|
||||||
func H264() RTPCodec {
|
func H264() RTPCodec {
|
||||||
return RTPCodec{
|
return RTPCodec{
|
||||||
Name: "h264",
|
Name: "h264",
|
||||||
PayloadType: 102,
|
PayloadType: 102,
|
||||||
Type: webrtc.RTPCodecTypeVideo,
|
Type: webrtc.RTPCodecTypeVideo,
|
||||||
Capability: webrtc.RTPCodecCapability{
|
Capability: webrtc.RTPCodecCapability{
|
||||||
MimeType: webrtc.MimeTypeH264,
|
MimeType: webrtc.MimeTypeH264,
|
||||||
ClockRate: 90000,
|
ClockRate: 90000,
|
||||||
Channels: 0,
|
Channels: 0,
|
||||||
SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f",
|
SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f",
|
||||||
RTCPFeedback: nil,
|
RTCPFeedback: nil,
|
||||||
},
|
},
|
||||||
// https://gstreamer.freedesktop.org/documentation/x264/index.html
|
// https://gstreamer.freedesktop.org/documentation/x264/index.html
|
||||||
@ -78,14 +78,14 @@ func H264() RTPCodec {
|
|||||||
|
|
||||||
func Opus() RTPCodec {
|
func Opus() RTPCodec {
|
||||||
return RTPCodec{
|
return RTPCodec{
|
||||||
Name: "opus",
|
Name: "opus",
|
||||||
PayloadType: 111,
|
PayloadType: 111,
|
||||||
Type: webrtc.RTPCodecTypeAudio,
|
Type: webrtc.RTPCodecTypeAudio,
|
||||||
Capability: webrtc.RTPCodecCapability{
|
Capability: webrtc.RTPCodecCapability{
|
||||||
MimeType: webrtc.MimeTypeOpus,
|
MimeType: webrtc.MimeTypeOpus,
|
||||||
ClockRate: 48000,
|
ClockRate: 48000,
|
||||||
Channels: 2,
|
Channels: 2,
|
||||||
SDPFmtpLine: "",
|
SDPFmtpLine: "",
|
||||||
RTCPFeedback: nil,
|
RTCPFeedback: nil,
|
||||||
},
|
},
|
||||||
// https://gstreamer.freedesktop.org/documentation/opus/opusenc.html
|
// https://gstreamer.freedesktop.org/documentation/opus/opusenc.html
|
||||||
@ -96,14 +96,14 @@ func Opus() RTPCodec {
|
|||||||
|
|
||||||
func G722() RTPCodec {
|
func G722() RTPCodec {
|
||||||
return RTPCodec{
|
return RTPCodec{
|
||||||
Name: "g722",
|
Name: "g722",
|
||||||
PayloadType: 9,
|
PayloadType: 9,
|
||||||
Type: webrtc.RTPCodecTypeAudio,
|
Type: webrtc.RTPCodecTypeAudio,
|
||||||
Capability: webrtc.RTPCodecCapability{
|
Capability: webrtc.RTPCodecCapability{
|
||||||
MimeType: webrtc.MimeTypeG722,
|
MimeType: webrtc.MimeTypeG722,
|
||||||
ClockRate: 8000,
|
ClockRate: 8000,
|
||||||
Channels: 0,
|
Channels: 0,
|
||||||
SDPFmtpLine: "",
|
SDPFmtpLine: "",
|
||||||
RTCPFeedback: nil,
|
RTCPFeedback: nil,
|
||||||
},
|
},
|
||||||
// https://gstreamer.freedesktop.org/documentation/libav/avenc_g722.html
|
// https://gstreamer.freedesktop.org/documentation/libav/avenc_g722.html
|
||||||
@ -114,14 +114,14 @@ func G722() RTPCodec {
|
|||||||
|
|
||||||
func PCMU() RTPCodec {
|
func PCMU() RTPCodec {
|
||||||
return RTPCodec{
|
return RTPCodec{
|
||||||
Name: "pcmu",
|
Name: "pcmu",
|
||||||
PayloadType: 0,
|
PayloadType: 0,
|
||||||
Type: webrtc.RTPCodecTypeAudio,
|
Type: webrtc.RTPCodecTypeAudio,
|
||||||
Capability: webrtc.RTPCodecCapability{
|
Capability: webrtc.RTPCodecCapability{
|
||||||
MimeType: webrtc.MimeTypePCMU,
|
MimeType: webrtc.MimeTypePCMU,
|
||||||
ClockRate: 8000,
|
ClockRate: 8000,
|
||||||
Channels: 0,
|
Channels: 0,
|
||||||
SDPFmtpLine: "",
|
SDPFmtpLine: "",
|
||||||
RTCPFeedback: nil,
|
RTCPFeedback: nil,
|
||||||
},
|
},
|
||||||
// https://gstreamer.freedesktop.org/documentation/mulaw/mulawenc.html
|
// https://gstreamer.freedesktop.org/documentation/mulaw/mulawenc.html
|
||||||
@ -132,14 +132,14 @@ func PCMU() RTPCodec {
|
|||||||
|
|
||||||
func PCMA() RTPCodec {
|
func PCMA() RTPCodec {
|
||||||
return RTPCodec{
|
return RTPCodec{
|
||||||
Name: "pcma",
|
Name: "pcma",
|
||||||
PayloadType: 8,
|
PayloadType: 8,
|
||||||
Type: webrtc.RTPCodecTypeAudio,
|
Type: webrtc.RTPCodecTypeAudio,
|
||||||
Capability: webrtc.RTPCodecCapability{
|
Capability: webrtc.RTPCodecCapability{
|
||||||
MimeType: webrtc.MimeTypePCMA,
|
MimeType: webrtc.MimeTypePCMA,
|
||||||
ClockRate: 8000,
|
ClockRate: 8000,
|
||||||
Channels: 0,
|
Channels: 0,
|
||||||
SDPFmtpLine: "",
|
SDPFmtpLine: "",
|
||||||
RTCPFeedback: nil,
|
RTCPFeedback: nil,
|
||||||
},
|
},
|
||||||
// https://gstreamer.freedesktop.org/documentation/alaw/alawenc.html
|
// https://gstreamer.freedesktop.org/documentation/alaw/alawenc.html
|
||||||
|
@ -73,7 +73,7 @@ type DesktopManager interface {
|
|||||||
OnEventError(listener func(error_code uint8, message string, request_code uint8, minor_code uint8))
|
OnEventError(listener func(error_code uint8, message string, request_code uint8, minor_code uint8))
|
||||||
|
|
||||||
// clipboard
|
// clipboard
|
||||||
ClipboardGetText() (*ClipboardText, error)
|
ClipboardGetText() (*ClipboardText, error)
|
||||||
ClipboardSetText(data ClipboardText) error
|
ClipboardSetText(data ClipboardText) error
|
||||||
ClipboardGetBinary(mime string) ([]byte, error)
|
ClipboardGetBinary(mime string) ([]byte, error)
|
||||||
ClipboardSetBinary(mime string, data []byte) error
|
ClipboardSetBinary(mime string, data []byte) error
|
||||||
|
@ -15,20 +15,20 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MEMBER_CREATED = "member/created"
|
MEMBER_CREATED = "member/created"
|
||||||
MEMBER_DELETED = "member/deleted"
|
MEMBER_DELETED = "member/deleted"
|
||||||
MEMBER_PROFILE = "member/profile"
|
MEMBER_PROFILE = "member/profile"
|
||||||
MEMBER_STATE = "member/state"
|
MEMBER_STATE = "member/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CONTROL_HOST = "control/host"
|
CONTROL_HOST = "control/host"
|
||||||
CONTROL_RELEASE = "control/release"
|
CONTROL_RELEASE = "control/release"
|
||||||
CONTROL_REQUEST = "control/request"
|
CONTROL_REQUEST = "control/request"
|
||||||
CONTROL_MOVE = "control/move" // TODO: New. (fallback)
|
CONTROL_MOVE = "control/move" // TODO: New. (fallback)
|
||||||
CONTROL_SCROLL = "control/scroll" // TODO: New. (fallback)
|
CONTROL_SCROLL = "control/scroll" // TODO: New. (fallback)
|
||||||
CONTROL_KEYDOWN = "control/keydown" // TODO: New. (fallback)
|
CONTROL_KEYDOWN = "control/keydown" // TODO: New. (fallback)
|
||||||
CONTROL_KEYUP = "control/keyup" // TODO: New. (fallback)
|
CONTROL_KEYUP = "control/keyup" // TODO: New. (fallback)
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -25,9 +25,9 @@ type SystemInit struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SystemAdmin struct {
|
type SystemAdmin struct {
|
||||||
Event string `json:"event,omitempty"`
|
Event string `json:"event,omitempty"`
|
||||||
ScreenSizesList []ScreenSize `json:"screen_sizes_list"`
|
ScreenSizesList []ScreenSize `json:"screen_sizes_list"`
|
||||||
BroadcastStatus BroadcastStatus `json:"broadcast_status"`
|
BroadcastStatus BroadcastStatus `json:"broadcast_status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SystemDisconnect struct {
|
type SystemDisconnect struct {
|
||||||
@ -96,9 +96,9 @@ type MemberData struct {
|
|||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
|
|
||||||
type ControlHost struct {
|
type ControlHost struct {
|
||||||
Event string `json:"event,omitempty"`
|
Event string `json:"event,omitempty"`
|
||||||
HasHost bool `json:"has_host"`
|
HasHost bool `json:"has_host"`
|
||||||
HostID string `json:"host_id,omitempty"`
|
HostID string `json:"host_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: New.
|
// TODO: New.
|
||||||
@ -155,7 +155,7 @@ type KeyboardModifiers struct {
|
|||||||
Event string `json:"event,omitempty"`
|
Event string `json:"event,omitempty"`
|
||||||
CapsLock *bool `json:"caps_lock"`
|
CapsLock *bool `json:"caps_lock"`
|
||||||
NumLock *bool `json:"num_lock"`
|
NumLock *bool `json:"num_lock"`
|
||||||
ScrollLock *bool `json:"scroll_lock"`
|
ScrollLock *bool `json:"scroll_lock"`
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
|
@ -22,9 +22,9 @@ type MembersDatabase interface {
|
|||||||
Connect() error
|
Connect() error
|
||||||
Disconnect() error
|
Disconnect() error
|
||||||
|
|
||||||
Insert(id string, profile MemberProfile) error
|
Insert(id string, profile MemberProfile) error
|
||||||
Update(id string, profile MemberProfile) error
|
Update(id string, profile MemberProfile) error
|
||||||
Delete(id string) error
|
Delete(id string) error
|
||||||
Select() (map[string]MemberProfile, error)
|
Select() (map[string]MemberProfile, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,10 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/png"
|
"image/png"
|
||||||
"encoding/base64"
|
|
||||||
|
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
)
|
)
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
@ -9,11 +9,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OP_MOVE = 0x01
|
OP_MOVE = 0x01
|
||||||
OP_SCROLL = 0x02
|
OP_SCROLL = 0x02
|
||||||
OP_KEY_DOWN = 0x03
|
OP_KEY_DOWN = 0x03
|
||||||
OP_KEY_UP = 0x04
|
OP_KEY_UP = 0x04
|
||||||
OP_KEY_CLK = 0x05
|
OP_KEY_CLK = 0x05
|
||||||
)
|
)
|
||||||
|
|
||||||
type PayloadHeader struct {
|
type PayloadHeader struct {
|
||||||
|
@ -8,17 +8,17 @@ import (
|
|||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
|
|
||||||
type nulllog struct {}
|
type nulllog struct{}
|
||||||
|
|
||||||
func (l nulllog) Trace(msg string) {}
|
func (l nulllog) Trace(msg string) {}
|
||||||
func (l nulllog) Tracef(format string, args ...interface{}) {}
|
func (l nulllog) Tracef(format string, args ...interface{}) {}
|
||||||
func (l nulllog) Debug(msg string) {}
|
func (l nulllog) Debug(msg string) {}
|
||||||
func (l nulllog) Debugf(format string, args ...interface{}) {}
|
func (l nulllog) Debugf(format string, args ...interface{}) {}
|
||||||
func (l nulllog) Info(msg string) {}
|
func (l nulllog) Info(msg string) {}
|
||||||
func (l nulllog) Infof(format string, args ...interface{}) {}
|
func (l nulllog) Infof(format string, args ...interface{}) {}
|
||||||
func (l nulllog) Warn(msg string) {}
|
func (l nulllog) Warn(msg string) {}
|
||||||
func (l nulllog) Warnf(format string, args ...interface{}) {}
|
func (l nulllog) Warnf(format string, args ...interface{}) {}
|
||||||
func (l nulllog) Error(msg string) {}
|
func (l nulllog) Error(msg string) {}
|
||||||
func (l nulllog) Errorf(format string, args ...interface{}) {}
|
func (l nulllog) Errorf(format string, args ...interface{}) {}
|
||||||
|
|
||||||
type logger struct {
|
type logger struct {
|
||||||
|
@ -3,39 +3,39 @@ package webrtc
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/pion/webrtc/v3"
|
"github.com/pion/webrtc/v3"
|
||||||
"github.com/pion/webrtc/v3/pkg/media"
|
"github.com/pion/webrtc/v3/pkg/media"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"demodesk/neko/internal/config"
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/types/event"
|
"demodesk/neko/internal/types/event"
|
||||||
"demodesk/neko/internal/types/message"
|
"demodesk/neko/internal/types/message"
|
||||||
"demodesk/neko/internal/config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(desktop types.DesktopManager, capture types.CaptureManager, config *config.WebRTC) *WebRTCManagerCtx {
|
func New(desktop types.DesktopManager, capture types.CaptureManager, config *config.WebRTC) *WebRTCManagerCtx {
|
||||||
return &WebRTCManagerCtx{
|
return &WebRTCManagerCtx{
|
||||||
logger: log.With().Str("module", "webrtc").Logger(),
|
logger: log.With().Str("module", "webrtc").Logger(),
|
||||||
desktop: desktop,
|
desktop: desktop,
|
||||||
capture: capture,
|
capture: capture,
|
||||||
config: config,
|
config: config,
|
||||||
// TODO: Refactor.
|
// TODO: Refactor.
|
||||||
curImgListeners: map[uintptr]*func(cur *types.CursorImage){},
|
curImgListeners: map[uintptr]*func(cur *types.CursorImage){},
|
||||||
curPosListeners: map[uintptr]*func(x, y int){},
|
curPosListeners: map[uintptr]*func(x, y int){},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebRTCManagerCtx struct {
|
type WebRTCManagerCtx struct {
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
audioTrack *webrtc.TrackLocalStaticSample
|
audioTrack *webrtc.TrackLocalStaticSample
|
||||||
audioStop func()
|
audioStop func()
|
||||||
desktop types.DesktopManager
|
desktop types.DesktopManager
|
||||||
capture types.CaptureManager
|
capture types.CaptureManager
|
||||||
config *config.WebRTC
|
config *config.WebRTC
|
||||||
// TODO: Refactor.
|
// TODO: Refactor.
|
||||||
curImgListeners map[uintptr]*func(cur *types.CursorImage)
|
curImgListeners map[uintptr]*func(cur *types.CursorImage)
|
||||||
curPosListeners map[uintptr]*func(x, y int)
|
curPosListeners map[uintptr]*func(x, y int)
|
||||||
@ -58,7 +58,7 @@ func (manager *WebRTCManagerCtx) Start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
audio.AddListener(&listener)
|
audio.AddListener(&listener)
|
||||||
manager.audioStop = func(){
|
manager.audioStop = func() {
|
||||||
audio.RemoveListener(&listener)
|
audio.RemoveListener(&listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ func (manager *WebRTCManagerCtx) CreatePeer(session types.Session, videoID strin
|
|||||||
if videoStream.ListenersCount() == 0 {
|
if videoStream.ListenersCount() == 0 {
|
||||||
videoStream.Stop()
|
videoStream.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
videoStream = newVideoStream
|
videoStream = newVideoStream
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -234,10 +234,10 @@ func (manager *WebRTCManagerCtx) CreatePeer(session types.Session, videoID strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
peer := &WebRTCPeerCtx{
|
peer := &WebRTCPeerCtx{
|
||||||
api: api,
|
api: api,
|
||||||
connection: connection,
|
connection: connection,
|
||||||
changeVideo: changeVideo,
|
changeVideo: changeVideo,
|
||||||
dataChannel: dataChannel,
|
dataChannel: dataChannel,
|
||||||
}
|
}
|
||||||
|
|
||||||
cursorChange := func(cur *types.CursorImage) {
|
cursorChange := func(cur *types.CursorImage) {
|
||||||
|
@ -3,15 +3,15 @@ package webrtc
|
|||||||
import "github.com/pion/webrtc/v3"
|
import "github.com/pion/webrtc/v3"
|
||||||
|
|
||||||
type WebRTCPeerCtx struct {
|
type WebRTCPeerCtx struct {
|
||||||
api *webrtc.API
|
api *webrtc.API
|
||||||
connection *webrtc.PeerConnection
|
connection *webrtc.PeerConnection
|
||||||
dataChannel *webrtc.DataChannel
|
dataChannel *webrtc.DataChannel
|
||||||
changeVideo func(videoID string) error
|
changeVideo func(videoID string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (webrtc_peer *WebRTCPeerCtx) SignalAnswer(sdp string) error {
|
func (webrtc_peer *WebRTCPeerCtx) SignalAnswer(sdp string) error {
|
||||||
return webrtc_peer.connection.SetRemoteDescription(webrtc.SessionDescription{
|
return webrtc_peer.connection.SetRemoteDescription(webrtc.SessionDescription{
|
||||||
SDP: sdp,
|
SDP: sdp,
|
||||||
Type: webrtc.SDPTypeAnswer,
|
Type: webrtc.SDPTypeAnswer,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package webrtc
|
package webrtc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/utils"
|
"demodesk/neko/internal/utils"
|
||||||
@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
OP_CURSOR_POSITION = 0x01
|
OP_CURSOR_POSITION = 0x01
|
||||||
OP_CURSOR_IMAGE = 0x02
|
OP_CURSOR_IMAGE = 0x02
|
||||||
)
|
)
|
||||||
|
|
||||||
type PayloadCursorPosition struct {
|
type PayloadCursorPosition struct {
|
||||||
@ -35,7 +35,7 @@ func (webrtc_peer *WebRTCPeerCtx) SendCursorPosition(x, y int) error {
|
|||||||
|
|
||||||
data := PayloadCursorPosition{
|
data := PayloadCursorPosition{
|
||||||
PayloadHeader: PayloadHeader{
|
PayloadHeader: PayloadHeader{
|
||||||
Event: OP_CURSOR_POSITION,
|
Event: OP_CURSOR_POSITION,
|
||||||
Length: 7,
|
Length: 7,
|
||||||
},
|
},
|
||||||
X: uint16(x),
|
X: uint16(x),
|
||||||
@ -62,13 +62,13 @@ func (webrtc_peer *WebRTCPeerCtx) SendCursorImage(cur *types.CursorImage) error
|
|||||||
|
|
||||||
data := PayloadCursorImage{
|
data := PayloadCursorImage{
|
||||||
PayloadHeader: PayloadHeader{
|
PayloadHeader: PayloadHeader{
|
||||||
Event: OP_CURSOR_IMAGE,
|
Event: OP_CURSOR_IMAGE,
|
||||||
Length: uint16(11 + len(img)),
|
Length: uint16(11 + len(img)),
|
||||||
},
|
},
|
||||||
Width: cur.Width,
|
Width: cur.Width,
|
||||||
Height: cur.Height,
|
Height: cur.Height,
|
||||||
Xhot: cur.Xhot,
|
Xhot: cur.Xhot,
|
||||||
Yhot: cur.Yhot,
|
Yhot: cur.Yhot,
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer := &bytes.Buffer{}
|
buffer := &bytes.Buffer{}
|
||||||
|
@ -23,8 +23,8 @@ func (ws *WebSocketManagerCtx) fileChooserDialogEvents() {
|
|||||||
file_chooser_dialog_member = host
|
file_chooser_dialog_member = host
|
||||||
|
|
||||||
go ws.sessions.Broadcast(message.MemberID{
|
go ws.sessions.Broadcast(message.MemberID{
|
||||||
Event: event.FILE_CHOOSER_DIALOG_OPENED,
|
Event: event.FILE_CHOOSER_DIALOG_OPENED,
|
||||||
ID: host.ID(),
|
ID: host.ID(),
|
||||||
}, nil)
|
}, nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -35,11 +35,10 @@ func (ws *WebSocketManagerCtx) fileChooserDialogEvents() {
|
|||||||
file_chooser_dialog_member = nil
|
file_chooser_dialog_member = nil
|
||||||
|
|
||||||
go ws.sessions.Broadcast(message.MemberID{
|
go ws.sessions.Broadcast(message.MemberID{
|
||||||
Event: event.FILE_CHOOSER_DIALOG_CLOSED,
|
Event: event.FILE_CHOOSER_DIALOG_CLOSED,
|
||||||
}, nil)
|
}, nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// when new user joins, and someone holds dialog, he shouldd be notified about it.
|
// when new user joins, and someone holds dialog, he shouldd be notified about it.
|
||||||
ws.sessions.OnConnected(func(session types.Session) {
|
ws.sessions.OnConnected(func(session types.Session) {
|
||||||
if file_chooser_dialog_member == nil {
|
if file_chooser_dialog_member == nil {
|
||||||
@ -47,8 +46,8 @@ func (ws *WebSocketManagerCtx) fileChooserDialogEvents() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := session.Send(message.MemberID{
|
if err := session.Send(message.MemberID{
|
||||||
Event: event.FILE_CHOOSER_DIALOG_OPENED,
|
Event: event.FILE_CHOOSER_DIALOG_OPENED,
|
||||||
ID: file_chooser_dialog_member.ID(),
|
ID: file_chooser_dialog_member.ID(),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
ws.logger.Warn().
|
ws.logger.Warn().
|
||||||
Str("id", session.ID()).
|
Str("id", session.ID()).
|
||||||
|
@ -21,20 +21,20 @@ func New(
|
|||||||
logger := log.With().Str("module", "handler").Logger()
|
logger := log.With().Str("module", "handler").Logger()
|
||||||
|
|
||||||
return &MessageHandlerCtx{
|
return &MessageHandlerCtx{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
sessions: sessions,
|
sessions: sessions,
|
||||||
desktop: desktop,
|
desktop: desktop,
|
||||||
capture: capture,
|
capture: capture,
|
||||||
webrtc: webrtc,
|
webrtc: webrtc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type MessageHandlerCtx struct {
|
type MessageHandlerCtx struct {
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
sessions types.SessionManager
|
sessions types.SessionManager
|
||||||
webrtc types.WebRTCManager
|
webrtc types.WebRTCManager
|
||||||
desktop types.DesktopManager
|
desktop types.DesktopManager
|
||||||
capture types.CaptureManager
|
capture types.CaptureManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MessageHandlerCtx) Message(session types.Session, raw []byte) bool {
|
func (h *MessageHandlerCtx) Message(session types.Session, raw []byte) bool {
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"demodesk/neko/internal/types/message"
|
"demodesk/neko/internal/types/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func (h *MessageHandlerCtx) keyboardMap(session types.Session, payload *message.KeyboardMap) error {
|
func (h *MessageHandlerCtx) keyboardMap(session types.Session, payload *message.KeyboardMap) error {
|
||||||
if !session.IsHost() {
|
if !session.IsHost() {
|
||||||
h.logger.Debug().Str("id", session.ID()).Msg("is not the host")
|
h.logger.Debug().Str("id", session.ID()).Msg("is not the host")
|
||||||
@ -13,7 +12,7 @@ func (h *MessageHandlerCtx) keyboardMap(session types.Session, payload *message.
|
|||||||
}
|
}
|
||||||
|
|
||||||
return h.desktop.SetKeyboardMap(types.KeyboardMap{
|
return h.desktop.SetKeyboardMap(types.KeyboardMap{
|
||||||
Layout: payload.Layout,
|
Layout: payload.Layout,
|
||||||
Variant: payload.Variant,
|
Variant: payload.Variant,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -25,7 +24,7 @@ func (h *MessageHandlerCtx) keyboardModifiers(session types.Session, payload *me
|
|||||||
}
|
}
|
||||||
|
|
||||||
h.desktop.SetKeyboardModifiers(types.KeyboardModifiers{
|
h.desktop.SetKeyboardModifiers(types.KeyboardModifiers{
|
||||||
NumLock: payload.NumLock,
|
NumLock: payload.NumLock,
|
||||||
CapsLock: payload.CapsLock,
|
CapsLock: payload.CapsLock,
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
|
@ -13,9 +13,9 @@ func (h *MessageHandlerCtx) screenSet(session types.Session, payload *message.Sc
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := h.desktop.SetScreenSize(types.ScreenSize{
|
if err := h.desktop.SetScreenSize(types.ScreenSize{
|
||||||
Width: payload.Width,
|
Width: payload.Width,
|
||||||
Height: payload.Height,
|
Height: payload.Height,
|
||||||
Rate: payload.Rate,
|
Rate: payload.Rate,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@ package handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/types/message"
|
|
||||||
"demodesk/neko/internal/types/event"
|
"demodesk/neko/internal/types/event"
|
||||||
|
"demodesk/neko/internal/types/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *MessageHandlerCtx) sendUnicast(session types.Session, payload *message.SendUnicast) error {
|
func (h *MessageHandlerCtx) sendUnicast(session types.Session, payload *message.SendUnicast) error {
|
||||||
@ -24,10 +24,10 @@ func (h *MessageHandlerCtx) sendUnicast(session types.Session, payload *message.
|
|||||||
|
|
||||||
func (h *MessageHandlerCtx) sendBroadcast(session types.Session, payload *message.SendBroadcast) error {
|
func (h *MessageHandlerCtx) sendBroadcast(session types.Session, payload *message.SendBroadcast) error {
|
||||||
h.sessions.Broadcast(message.SendBroadcast{
|
h.sessions.Broadcast(message.SendBroadcast{
|
||||||
Event: event.SEND_BROADCAST,
|
Event: event.SEND_BROADCAST,
|
||||||
Sender: session.ID(),
|
Sender: session.ID(),
|
||||||
Subject: payload.Subject,
|
Subject: payload.Subject,
|
||||||
Body: payload.Body,
|
Body: payload.Body,
|
||||||
}, []string{ session.ID() })
|
}, []string{session.ID()})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ func (h *MessageHandlerCtx) SessionDeleted(session types.Session) error {
|
|||||||
message.MemberID{
|
message.MemberID{
|
||||||
Event: event.MEMBER_DELETED,
|
Event: event.MEMBER_DELETED,
|
||||||
ID: session.ID(),
|
ID: session.ID(),
|
||||||
}, nil);
|
}, nil)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ func (h *MessageHandlerCtx) signalVideo(session types.Session, payload *message.
|
|||||||
|
|
||||||
return session.Send(
|
return session.Send(
|
||||||
message.SignalVideo{
|
message.SignalVideo{
|
||||||
Event: event.SIGNAL_VIDEO,
|
Event: event.SIGNAL_VIDEO,
|
||||||
Video: payload.Video,
|
Video: payload.Video,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -34,10 +34,10 @@ func (h *MessageHandlerCtx) systemInit(session types.Session) error {
|
|||||||
|
|
||||||
return session.Send(
|
return session.Send(
|
||||||
message.SystemInit{
|
message.SystemInit{
|
||||||
Event: event.SYSTEM_INIT,
|
Event: event.SYSTEM_INIT,
|
||||||
MemberId: session.ID(),
|
MemberId: session.ID(),
|
||||||
ControlHost: controlHost,
|
ControlHost: controlHost,
|
||||||
ScreenSize: message.ScreenSize{
|
ScreenSize: message.ScreenSize{
|
||||||
Width: size.Width,
|
Width: size.Width,
|
||||||
Height: size.Height,
|
Height: size.Height,
|
||||||
Rate: size.Rate,
|
Rate: size.Rate,
|
||||||
|
@ -8,10 +8,10 @@ import (
|
|||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"demodesk/neko/internal/websocket/handler"
|
|
||||||
"demodesk/neko/internal/types"
|
"demodesk/neko/internal/types"
|
||||||
"demodesk/neko/internal/types/event"
|
"demodesk/neko/internal/types/event"
|
||||||
"demodesk/neko/internal/types/message"
|
"demodesk/neko/internal/types/message"
|
||||||
|
"demodesk/neko/internal/websocket/handler"
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
@ -23,11 +23,11 @@ func New(
|
|||||||
logger := log.With().Str("module", "websocket").Logger()
|
logger := log.With().Str("module", "websocket").Logger()
|
||||||
|
|
||||||
return &WebSocketManagerCtx{
|
return &WebSocketManagerCtx{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
sessions: sessions,
|
sessions: sessions,
|
||||||
desktop: desktop,
|
desktop: desktop,
|
||||||
handler: handler.New(sessions, desktop, capture, webrtc),
|
handler: handler.New(sessions, desktop, capture, webrtc),
|
||||||
handlers: []types.HandlerFunction{},
|
handlers: []types.HandlerFunction{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,12 +35,12 @@ func New(
|
|||||||
const pingPeriod = 60 * time.Second
|
const pingPeriod = 60 * time.Second
|
||||||
|
|
||||||
type WebSocketManagerCtx struct {
|
type WebSocketManagerCtx struct {
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
sessions types.SessionManager
|
sessions types.SessionManager
|
||||||
desktop types.DesktopManager
|
desktop types.DesktopManager
|
||||||
handler *handler.MessageHandlerCtx
|
handler *handler.MessageHandlerCtx
|
||||||
handlers []types.HandlerFunction
|
handlers []types.HandlerFunction
|
||||||
shutdown chan bool
|
shutdown chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *WebSocketManagerCtx) Start() {
|
func (ws *WebSocketManagerCtx) Start() {
|
||||||
|
54
neko.go
54
neko.go
@ -6,14 +6,14 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"demodesk/neko/internal/api"
|
||||||
|
"demodesk/neko/internal/capture"
|
||||||
"demodesk/neko/internal/config"
|
"demodesk/neko/internal/config"
|
||||||
"demodesk/neko/internal/desktop"
|
"demodesk/neko/internal/desktop"
|
||||||
"demodesk/neko/internal/capture"
|
|
||||||
"demodesk/neko/internal/webrtc"
|
|
||||||
"demodesk/neko/internal/session"
|
|
||||||
"demodesk/neko/internal/websocket"
|
|
||||||
"demodesk/neko/internal/api"
|
|
||||||
"demodesk/neko/internal/http"
|
"demodesk/neko/internal/http"
|
||||||
|
"demodesk/neko/internal/session"
|
||||||
|
"demodesk/neko/internal/webrtc"
|
||||||
|
"demodesk/neko/internal/websocket"
|
||||||
"demodesk/neko/modules"
|
"demodesk/neko/modules"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
@ -62,12 +62,12 @@ func init() {
|
|||||||
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
|
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
|
||||||
},
|
},
|
||||||
Configs: &Configs{
|
Configs: &Configs{
|
||||||
Root: &config.Root{},
|
Root: &config.Root{},
|
||||||
Desktop: &config.Desktop{},
|
Desktop: &config.Desktop{},
|
||||||
Capture: &config.Capture{},
|
Capture: &config.Capture{},
|
||||||
WebRTC: &config.WebRTC{},
|
WebRTC: &config.WebRTC{},
|
||||||
Session: &config.Session{},
|
Session: &config.Session{},
|
||||||
Server: &config.Server{},
|
Server: &config.Server{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,26 +102,26 @@ func (i *Version) Details() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Configs struct {
|
type Configs struct {
|
||||||
Root *config.Root
|
Root *config.Root
|
||||||
Desktop *config.Desktop
|
Desktop *config.Desktop
|
||||||
Capture *config.Capture
|
Capture *config.Capture
|
||||||
WebRTC *config.WebRTC
|
WebRTC *config.WebRTC
|
||||||
Session *config.Session
|
Session *config.Session
|
||||||
Server *config.Server
|
Server *config.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
type Neko struct {
|
type Neko struct {
|
||||||
Version *Version
|
Version *Version
|
||||||
Configs *Configs
|
Configs *Configs
|
||||||
|
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
desktopManager *desktop.DesktopManagerCtx
|
desktopManager *desktop.DesktopManagerCtx
|
||||||
captureManager *capture.CaptureManagerCtx
|
captureManager *capture.CaptureManagerCtx
|
||||||
webRTCManager *webrtc.WebRTCManagerCtx
|
webRTCManager *webrtc.WebRTCManagerCtx
|
||||||
sessionManager *session.SessionManagerCtx
|
sessionManager *session.SessionManagerCtx
|
||||||
webSocketManager *websocket.WebSocketManagerCtx
|
webSocketManager *websocket.WebSocketManagerCtx
|
||||||
apiManager *api.ApiManagerCtx
|
apiManager *api.ApiManagerCtx
|
||||||
httpManager *http.HttpManagerCtx
|
httpManager *http.HttpManagerCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (neko *Neko) Preflight() {
|
func (neko *Neko) Preflight() {
|
||||||
|
Loading…
Reference in New Issue
Block a user