Skip to content

Commit

Permalink
all: resolve service lunch issue on windows (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
kvii authored Sep 25, 2022
1 parent dae1910 commit e6cf1b2
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 112 deletions.
48 changes: 32 additions & 16 deletions api/daemon/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"log"
"net"
"os"
"os/signal"
"sync"
"time"

Expand Down Expand Up @@ -44,7 +43,7 @@ func NewDaemon() *Daemon {
if err != nil {
id, err = utils.NewUUIDShort()
if err != nil {
panic(fmt.Errorf("failed to initialize deamon: %v", err))
panic(fmt.Errorf("failed to initialize daemon: %v", err))
}
}
return &Daemon{
Expand All @@ -54,32 +53,49 @@ func NewDaemon() *Daemon {
}
}

// Serve serves Daemon daemon:
// Run runs Daemon daemon:
// 1. maintaining midgard daemon rpc;
// 2. maintaining midgard daemon to server websocket.
func (m *Daemon) Serve() {
ctx, cancel := context.WithCancel(context.Background())
func (m *Daemon) Run(ctx context.Context) (onStart, onStop func() error) {
wg := sync.WaitGroup{}
ctx, cancel := context.WithCancel(ctx)

run := func() {
defer wg.Done()
m.Serve(ctx)
}

onStart = func() error {
wg.Add(1)
go run()
return nil
}
onStop = func() error {
cancel()
wg.Wait()
return nil
}
return
}

// Serve serves Daemon daemon:
// 1. maintaining midgard daemon rpc;
// 2. maintaining midgard daemon to server websocket.
func (m *Daemon) Serve(ctx context.Context) {
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
defer func() {
log.Println("graceful shutdown assistant is terminated.")
}()
q := make(chan os.Signal, 1)
signal.Notify(q, os.Interrupt)
sig := <-q
log.Printf("%v", sig)
log.Printf("shutting down midgard daemon ...")
defer log.Println("graceful shutdown assistant is terminated.")
<-ctx.Done()
m.s.GracefulStop()
cancel()
}()
wg.Add(1)
go func() {
defer wg.Done()
defer log.Println("websocket is terminated.")
m.wsConnect()
m.handleIO(ctx)
m.wsClose()
}()
wg.Add(1)
go func() {
Expand Down Expand Up @@ -109,7 +125,7 @@ const maxMessageSize = 10 << 20 // 10 MB
func (m *Daemon) serveRPC() {
l, err := net.Listen("tcp", config.D().Addr)
if err != nil {
log.Fatalf("fail to initalize midgard daemon, err: %v", err)
log.Fatalf("fail to initialize midgard daemon, err: %v", err)
}

m.s = grpc.NewServer(
Expand Down
76 changes: 37 additions & 39 deletions api/daemon/ws.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"log"
"net/http"
"strings"
"sync"
"time"

"changkun.de/x/midgard/internal/clipboard"
Expand Down Expand Up @@ -78,10 +77,6 @@ func (m *Daemon) wsConnect() error {
return nil
}

func (m *Daemon) wsClose() {
m.ws.Close()
}

// wsReconnect tries to reconnect to the midgard server and returns
// until it connects to the server.
func (m *Daemon) wsReconnect(ctx context.Context) {
Expand Down Expand Up @@ -110,40 +105,9 @@ func (m *Daemon) handleIO(ctx context.Context) {
}

log.Println("daemon id:", m.ID)
wg := sync.WaitGroup{}
wg.Add(2)
go func() { // read from server
defer wg.Done()
m.readFromServer(ctx)
}()
go func() { // write to server
defer wg.Done()
for {
select {
case <-ctx.Done():
if m.ws == nil {
log.Println("connection was not ready")
return
}
_ = m.ws.WriteMessage(websocket.BinaryMessage, (&types.WebsocketMessage{
Action: types.ActionTerminate,
UserID: m.ID,
}).Encode())
return
case msg := <-m.writeCh:
if m.ws == nil {
log.Println("connection is not ready yet")
continue
}
err := m.ws.WriteMessage(websocket.BinaryMessage, msg.Encode())
if err != nil {
log.Printf("failed to write message to server: %v", err)
return
}
}
}
}()
wg.Wait()
go m.readFromServer(ctx)
m.writeToServer(ctx)
m.wsClose()
}

func (m *Daemon) readFromServer(ctx context.Context) {
Expand Down Expand Up @@ -203,3 +167,37 @@ func (m *Daemon) readFromServer(ctx context.Context) {
}
}
}

func (m *Daemon) writeToServer(ctx context.Context) {
for {
select {
case <-ctx.Done():
if m.ws == nil {
log.Println("connection was not ready")
}
return
case msg := <-m.writeCh:
if m.ws == nil {
log.Println("connection is not ready yet")
continue
}
err := m.ws.WriteMessage(websocket.BinaryMessage, msg.Encode())
if err != nil {
log.Printf("failed to write message to server: %v", err)
return
}
}
}
}

func (m *Daemon) wsClose() {
_ = m.ws.WriteMessage(websocket.BinaryMessage, (&types.WebsocketMessage{
Action: types.ActionTerminate,
UserID: m.ID,
}).Encode())

h := m.ws.CloseHandler()
h(websocket.CloseNormalClosure, "")

m.ws.Close()
}
2 changes: 1 addition & 1 deletion cmd/code2img.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ var code2imgCmd = &cobra.Command{
}

if len(out.CodeURL) == 0 && len(out.ImageURL) == 0 {
log.Println("nothing was convereted to image.")
log.Println("nothing was converted to image.")
return
}

Expand Down
8 changes: 6 additions & 2 deletions cmd/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,12 @@ var daemonCmd = &cobra.Command{
err = s.Stop()
case "run":
m := daemon.NewDaemon()
m.Serve()
os.Exit(0) // this closes clipboard NSApplication on darwin
onStart, onStop := m.Run(context.Background())

err = s.Run(onStart, onStop)
if err == nil {
os.Exit(0) // this closes clipboard NSApplication on darwin
}
case "ls":
daemon.Connect(func(ctx context.Context, c proto.MidgardClient) {
out, err := c.ListDaemons(ctx, &proto.ListDaemonsInput{})
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ require (
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554 // indirect
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
golang.org/x/sync v0.0.0-20220907140024-f12130a52804
golang.org/x/text v0.3.6 // indirect
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220907140024-f12130a52804 h1:0SH2R3f1b1VmIMG7BXbEZCBUu2dKmHschSmjqGUrW8A=
golang.org/x/sync v0.0.0-20220907140024-f12130a52804/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
27 changes: 27 additions & 0 deletions internal/service/service_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package service

import (
"fmt"
"os"
"os/signal"

"changkun.de/x/midgard/internal/osext"
"golang.org/x/sys/windows/svc"
Expand Down Expand Up @@ -124,6 +126,31 @@ func (ws *windowsService) Run(onStart, onStop func() error) error {

ws.logger = elog

// only service can use windows api.
isService, err := svc.IsWindowsService()
if err != nil {
return err
}
if isService {
return ws.runIsService(onStart, onStop)
}
return ws.runNotService(onStart, onStop)
}

func (ws *windowsService) runNotService(onStart, onStop func() error) error {
err := onStart()
if err != nil {
return err
}

sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)
<-sigChan

return onStop()
}

func (ws *windowsService) runIsService(onStart, onStop func() error) error {
ws.onStart = onStart
ws.onStop = onStop
return svc.Run(ws.name, ws)
Expand Down
Loading

0 comments on commit e6cf1b2

Please sign in to comment.