diff --git a/cmd/server/server.go b/cmd/server/server.go index 31fe436..fc7adef 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -38,10 +38,16 @@ func (s *Server) Run() error { gin.SetMode(gin.ReleaseMode) } - qemuserver.Setup(s.options.Qemu) - webserver.Setup(s.options.WEBServer) - <-make(chan int) - return nil + if err := qemuserver.Setup(s.options.Qemu); err != nil { + return err + } + + webServer, err := webserver.NewServer(s.options.WEBServer) + if err != nil { + return err + } + + return webServer.Run() } func runServer(c *cli.Context) error { diff --git a/lib/qemuconnection/events.go b/lib/qemuconnection/events.go index 9c1f9b1..3ece627 100644 --- a/lib/qemuconnection/events.go +++ b/lib/qemuconnection/events.go @@ -77,14 +77,10 @@ func makeControlCommand(t int) []qmp.Command { } func makeHMCommand(cmdTemplate string, args ...any) qmp.Command { - template := qmp.Command{ + return qmp.Command{ Execute: "human-monitor-command", + Args: CommandLine{ + Command: fmt.Sprintf(cmdTemplate, args...), + }, } - command := CommandLine{ - Command: fmt.Sprintf(cmdTemplate, args...), - } - - template.Args = command - - return template } diff --git a/lib/qemuconnection/loginit.go b/lib/qemuconnection/loginit.go deleted file mode 100644 index 5c290e5..0000000 --- a/lib/qemuconnection/loginit.go +++ /dev/null @@ -1,7 +0,0 @@ -package qemuconnection - -import "github.com/sirupsen/logrus" - -func init() { - logrus.Info("qemu client control events module loaded") -} diff --git a/lib/webrtcconnection/connection.go b/lib/webrtcconnection/connection.go index 14456ea..d9dc9ff 100644 --- a/lib/webrtcconnection/connection.go +++ b/lib/webrtcconnection/connection.go @@ -12,26 +12,41 @@ const DefaultStreamID = "ace-server" type Connection struct { option *Options + api *webrtc.API + stream mediadevices.MediaStream } -func New(o *Options) *Connection { - return &Connection{ +func New(o *Options) (*Connection, error) { + connection := &Connection{ option: o, } -} - -func (c *Connection) Regist(offer *webrtc.SessionDescription) (*webrtc.SessionDescription, error) { - logrus.Debug("received offer ", offer.Type.String()) - codecSelector, err := setupCodec(c.option.Video.BPS, c.option.Audio.BPS) + codecSelector, err := setupCodec(o.Video.BPS, o.Audio.BPS) if err != nil { return nil, err } me := &webrtc.MediaEngine{} codecSelector.Populate(me) - api := webrtc.NewAPI(webrtc.WithMediaEngine(me)) - rtc, err := api.NewPeerConnection(webrtc.Configuration{ + connection.api = webrtc.NewAPI(webrtc.WithMediaEngine(me)) + + s, err := mediadevices.GetUserMedia(mediadevices.MediaStreamConstraints{ + Video: func(mtc *mediadevices.MediaTrackConstraints) {}, + Audio: func(mtc *mediadevices.MediaTrackConstraints) {}, + Codec: codecSelector, + }) + if err != nil { + return nil, err + } + connection.stream = s + + return connection, nil +} + +func (c *Connection) Regist(offer *webrtc.SessionDescription) (*webrtc.SessionDescription, error) { + logrus.Debug("received offer ", offer.Type.String()) + + rtc, err := c.api.NewPeerConnection(webrtc.Configuration{ ICEServers: []webrtc.ICEServer{ { URLs: c.option.STUNServers, @@ -53,21 +68,7 @@ func (c *Connection) Regist(offer *webrtc.SessionDescription) (*webrtc.SessionDe } }) - s, err := mediadevices.GetUserMedia(mediadevices.MediaStreamConstraints{ - Video: func(mtc *mediadevices.MediaTrackConstraints) { - /* - mtc.Height = prop.IntExact(c.option.Video.Height) - mtc.Width = prop.IntExact(c.option.Video.Width) - */ - }, - Audio: func(mtc *mediadevices.MediaTrackConstraints) {}, - Codec: codecSelector, - }) - if err != nil { - return nil, err - } - - for _, track := range s.GetTracks() { + for _, track := range c.stream.GetTracks() { track.OnEnded(func(err error) { logrus.Errorf("Track (ID: %s) ended with error: %v", track.ID(), err) }) diff --git a/lib/webrtcconnection/loginit.go b/lib/webrtcconnection/loginit.go deleted file mode 100644 index f25b2b8..0000000 --- a/lib/webrtcconnection/loginit.go +++ /dev/null @@ -1,7 +0,0 @@ -package webrtcconnection - -import "github.com/sirupsen/logrus" - -func init() { - logrus.Info("webrtc connection module initialized") -} diff --git a/main.go b/main.go index 656e589..218593d 100644 --- a/main.go +++ b/main.go @@ -10,7 +10,7 @@ import ( ) func init() { - logrus.Info("Starting...") + logrus.SetReportCaller(true) } func main() { diff --git a/servers/qemuserver/loginit.go b/servers/qemuserver/loginit.go deleted file mode 100644 index b225cbb..0000000 --- a/servers/qemuserver/loginit.go +++ /dev/null @@ -1,7 +0,0 @@ -package qemuserver - -import "github.com/sirupsen/logrus" - -func init() { - logrus.Info("qemu server loaded") -} diff --git a/servers/qemuserver/server.go b/servers/qemuserver/server.go index baf0ebc..4bc0ac7 100644 --- a/servers/qemuserver/server.go +++ b/servers/qemuserver/server.go @@ -19,25 +19,25 @@ type Server struct { RX chan *qemuconnection.Event TX chan qemu.Status } + qemu *qemu.Domain } var DefaultServer *Server -func NewServer(o *Options) *Server { +func NewServer(o *Options) (*Server, error) { + if err := o.MakeFIFO(); err != nil { + return nil, err + } + server := &Server{ options: o, } server.QmpConnector.RX = make(chan *qemuconnection.Event) server.QmpConnector.TX = make(chan qemu.Status) - return server -} -func (s *Server) Run() error { - logrus.Debug("qemu server running") - defer logrus.Debug("qemu server exit") - u, err := url.Parse(s.options.QmpAddress) + u, err := url.Parse(o.QmpAddress) if err != nil { - return err + return nil, err } var address string if u.Scheme == "unix" { @@ -46,29 +46,57 @@ func (s *Server) Run() error { address = u.Host } logrus.Debugf("trying to connect qmp with %s://%s", u.Scheme, address) - qmpConnection, err := qmp.NewSocketMonitor(u.Scheme, address, s.options.Timeout) + qmpConnection, err := qmp.NewSocketMonitor(u.Scheme, address, o.Timeout) if err != nil { - return err + return nil, err } - defer qmpConnection.Disconnect() if err := qmpConnection.Connect(); err != nil { - return err + return nil, err } logrus.Debug("qmp connected") - qemu, err := qemu.NewDomain(qmpConnection, s.options.Name) + qemu, err := qemu.NewDomain(qmpConnection, o.Name) if err != nil { - return err + return nil, err } - defer qemu.Close() + server.qemu = qemu - go s.startCapture(qemu) + if err := driver.GetManager().Register( + audiodriver.New(o.AudioPipe), + driver.Info{ + Label: "audioFifo", + DeviceType: driver.Microphone, + Priority: driver.PriorityNormal, + }, + ); err != nil { + return nil, err + } + if err := driver.GetManager().Register( + vncdriver.NewVnc(o.VNCAddress), + driver.Info{ + Label: "vnc", + DeviceType: driver.Camera, + Priority: driver.PriorityNormal, + }, + ); err != nil { + return nil, err + } + + return server, nil +} + +func (s *Server) Run() error { + logrus.Debug("qemu server running") + defer logrus.Debug("qemu server exit") + defer s.qemu.Close() + + go s.startCapture() logrus.Debug("qemu capture start") for ev := range s.QmpConnector.RX { if ev.Type == qemuconnection.QueryStatusEvent { - status, err := qemu.Status() + status, err := s.qemu.Status() if err != nil { logrus.Error("get qemu status error: ", err) continue @@ -77,43 +105,17 @@ func (s *Server) Run() error { continue } for _, cmd := range ev.ToQemuCommand() { - _, err := qemu.Run(cmd) + _, err := s.qemu.Run(cmd) if err != nil { logrus.Error("run command error: ", err) } - } } return nil } -func (s *Server) startCapture(qemu *qemu.Domain) { - if err := s.options.MakeFIFO(); err != nil { - logrus.Fatal("failed to make pipe file: ", err) - } - - if err := driver.GetManager().Register( - audiodriver.New(s.options.AudioPipe), - driver.Info{ - Label: "audioFifo", - DeviceType: driver.Microphone, - Priority: driver.PriorityNormal, - }, - ); err != nil { - logrus.Fatal("audio initialize failed: ", err) - } - if err := driver.GetManager().Register( - vncdriver.NewVnc(s.options.VNCAddress), - driver.Info{ - Label: "vnc", - DeviceType: driver.Camera, - Priority: driver.PriorityNormal, - }, - ); err != nil { - logrus.Fatal("video initialize failed: ", err) - } - - if _, err := qemu.Run(qmp.Command{ +func (s *Server) startCapture() { + if _, err := s.qemu.Run(qmp.Command{ Execute: "human-monitor-command", Args: map[string]string{ "command-line": fmt.Sprintf( @@ -128,13 +130,17 @@ func (s *Server) startCapture(qemu *qemu.Domain) { logrus.Debug("audio capture set") } -func Setup(o *Options) { - DefaultServer = NewServer(o) +func Setup(o *Options) error { + DefaultServer, err := NewServer(o) + if err != nil { + return err + } go func() { if err := DefaultServer.Run(); err != nil { logrus.Fatal("cannot run qemuserver with error: ", err) } }() + return nil } func SendEvent(b []byte) error { diff --git a/servers/webserver/loginit.go b/servers/webserver/loginit.go deleted file mode 100644 index bb1dba5..0000000 --- a/servers/webserver/loginit.go +++ /dev/null @@ -1,7 +0,0 @@ -package webserver - -import "github.com/sirupsen/logrus" - -func init() { - logrus.Info("web server loaded") -} diff --git a/servers/webserver/server.go b/servers/webserver/server.go index 1360044..4c6fd13 100644 --- a/servers/webserver/server.go +++ b/servers/webserver/server.go @@ -12,15 +12,18 @@ type Server struct { rtcConnector *webrtcconnection.Connection } -var DefaultServer *Server +func NewServer(o *Options) (*Server, error) { + rtc, err := webrtcconnection.New(o.WebRTC) + if err != nil { + return nil, err + } -func NewServer(o *Options) *Server { s := &Server{ options: o, webServer: gin.New(), - rtcConnector: webrtcconnection.New(o.WebRTC), + rtcConnector: rtc, } - return s + return s, nil } func (s *Server) Run() error { @@ -29,12 +32,3 @@ func (s *Server) Run() error { s.setupRoute() return s.webServer.Run(s.options.Listen) } - -func Setup(o *Options) { - DefaultServer = NewServer(o) - go func() { - if err := DefaultServer.Run(); err != nil { - logrus.Fatal("cannot run webserver with error: ", err) - } - }() -} diff --git a/servers/webserver/static.go b/servers/webserver/static.go index af18fc9..7defc87 100644 --- a/servers/webserver/static.go +++ b/servers/webserver/static.go @@ -26,8 +26,6 @@ func staticFileHandler() gin.HandlerFunc { defer ctx.Abort() filename := strings.TrimLeft(ctx.Request.RequestURI, "/") - logrus.Debug("static file: ", filename) - if filename == "" { filename = "index.html" } diff --git a/web/src/components/AceScreen.vue b/web/src/components/AceScreen.vue index bc49f70..d51b91a 100644 --- a/web/src/components/AceScreen.vue +++ b/web/src/components/AceScreen.vue @@ -74,8 +74,9 @@ onMounted(() => { }); pc.oniceconnectionstatechange = () => console.log(pc.iceConnectionState); pc.addTransceiver("video"); - //pc.addTransceiver('audio') - dataChannel = pc.createDataChannel("control"); + pc.addTransceiver("audio"); + + const dataChannel = pc.createDataChannel("control"); dataChannel.onmessage = (e) => { const d = JSON.parse(e.data); store.delay = +new Date() - d.server_time; @@ -86,48 +87,51 @@ onMounted(() => { video.autoplay = true; video.controls = false; }; - video.onmousemove = (ev) => { - dataChannel.send( - JSON.stringify( - makeEvent("mouseMove", { - dx: ev.clientX, - dy: ev.clientY, - dz: 0, - }) - ) - ); - }; - video.onmousedown = (ev) => { - dataChannel.send( - JSON.stringify( - makeEvent("mouseButton", { - button: ev.button << 1, - }) - ) - ); - }; - //video.onmousewheel = (ev) => {}; - window.onkeydown = (ev) => { - let key = ""; - if (ev.ctrlKey && ev.which !== 17) key = "ctrl-" + ev.key; - else key = "0x" + ev.which.toString(16); - if (ev.shiftKey && ev.which !== 16) key = "shift-" + ev.key; - else key = "0x" + ev.which.toString(16); - if (ev.altKey && ev.which !== 18) key = "alt-" + ev.key; - else key = "0x" + ev.which.toString(16); - if (ev.metaKey && ev.which !== 91 && ev.which !== 93) - key = "meta-" + ev.key; - else key = "0x" + ev.which.toString(16); - if (!ev.altKey && !ev.shiftKey && !ev.ctrlKey && !ev.metaKey) - key = "0x" + ev.which.toString(16); - dataChannel.send( - JSON.stringify( - makeEvent("keyboard", { - key: key, - }) - ) - ); + dataChannel.onopen = () => { + video.onmousemove = (ev) => { + dataChannel.send( + JSON.stringify( + makeEvent("mouseMove", { + dx: ev.clientX, + dy: ev.clientY, + dz: 0, + }) + ) + ); + }; + video.onmousedown = (ev) => { + dataChannel.send( + JSON.stringify( + makeEvent("mouseButton", { + button: ev.button << 1, + }) + ) + ); + }; + //video.onmousewheel = (ev) => {}; + window.onkeydown = (ev) => { + let key = ""; + if (ev.ctrlKey && ev.which !== 17) key = "ctrl-" + ev.key; + else key = "0x" + ev.which.toString(16); + if (ev.shiftKey && ev.which !== 16) key = "shift-" + ev.key; + else key = "0x" + ev.which.toString(16); + if (ev.altKey && ev.which !== 18) key = "alt-" + ev.key; + else key = "0x" + ev.which.toString(16); + if (ev.metaKey && ev.which !== 91 && ev.which !== 93) + key = "meta-" + ev.key; + else key = "0x" + ev.which.toString(16); + if (!ev.altKey && !ev.shiftKey && !ev.ctrlKey && !ev.metaKey) + key = "0x" + ev.which.toString(16); + + dataChannel.send( + JSON.stringify( + makeEvent("keyboard", { + key: key, + }) + ) + ); + }; }; pc.createOffer().then((offer) => {