5
5
"errors"
6
6
"fmt"
7
7
"io"
8
- "log/slog"
9
8
"net"
10
9
"net/http"
11
10
"os"
@@ -29,7 +28,15 @@ type Options struct {
29
28
Debug bool
30
29
}
31
30
32
- func Start (ctx context.Context , opts Options ) error {
31
+ // Run will start the server and block until the server is shut down.
32
+ func Run (ctx context.Context , opts Options ) error {
33
+ listener , err := newListener (opts )
34
+ if err != nil {
35
+ return err
36
+ }
37
+
38
+ fmt .Println (listener .Addr ().String ())
39
+
33
40
sigCtx , cancel := signal .NotifyContext (ctx , syscall .SIGTERM , syscall .SIGQUIT , syscall .SIGKILL )
34
41
defer cancel ()
35
42
go func () {
@@ -40,6 +47,32 @@ func Start(ctx context.Context, opts Options) error {
40
47
cancel ()
41
48
}()
42
49
50
+ return run (sigCtx , listener , opts )
51
+ }
52
+
53
+ // EmbeddedStart allows running the server as an embedded process that may use Stdin for input.
54
+ // It returns the address the server is listening on.
55
+ func EmbeddedStart (ctx context.Context , opts Options ) (string , error ) {
56
+ listener , err := newListener (opts )
57
+ if err != nil {
58
+ return "" , err
59
+ }
60
+
61
+ go run (ctx , listener , opts )
62
+
63
+ return listener .Addr ().String (), nil
64
+ }
65
+
66
+ func (s * server ) close () {
67
+ s .client .Close (true )
68
+ s .events .Close ()
69
+ }
70
+
71
+ func newListener (opts Options ) (net.Listener , error ) {
72
+ return net .Listen ("tcp" , opts .ListenAddress )
73
+ }
74
+
75
+ func run (ctx context.Context , listener net.Listener , opts Options ) error {
43
76
if opts .Debug {
44
77
mvl .SetDebug ()
45
78
}
@@ -58,11 +91,6 @@ func Start(ctx context.Context, opts Options) error {
58
91
return err
59
92
}
60
93
61
- listener , err := net .Listen ("tcp" , opts .ListenAddress )
62
- if err != nil {
63
- return fmt .Errorf ("failed to listen on %s: %w" , opts .ListenAddress , err )
64
- }
65
-
66
94
s := & server {
67
95
gptscriptOpts : opts .Options ,
68
96
address : listener .Addr ().String (),
@@ -72,11 +100,11 @@ func Start(ctx context.Context, opts Options) error {
72
100
waitingToConfirm : make (map [string ]chan runner.AuthorizerResponse ),
73
101
waitingToPrompt : make (map [string ]chan map [string ]string ),
74
102
}
75
- defer s .Close ()
103
+ defer s .close ()
76
104
77
105
s .addRoutes (http .DefaultServeMux )
78
106
79
- server := http.Server {
107
+ httpServer := & http.Server {
80
108
Handler : apply (http .DefaultServeMux ,
81
109
contentType ("application/json" ),
82
110
addRequestID ,
@@ -86,25 +114,22 @@ func Start(ctx context.Context, opts Options) error {
86
114
),
87
115
}
88
116
89
- slog . Info ( "Starting server" , "addr" , s . address )
90
-
91
- context .AfterFunc (sigCtx , func () {
92
- ctx , cancel := context .WithTimeout (ctx , 15 * time .Second )
117
+ logger := mvl . Package ( )
118
+ done := make ( chan struct {})
119
+ context .AfterFunc (ctx , func () {
120
+ ctx , cancel := context .WithTimeout (context . Background () , 15 * time .Second )
93
121
defer cancel ()
94
122
95
- slog .Info ("Shutting down server" )
96
- _ = server .Shutdown (ctx )
97
- slog .Info ("Server stopped" )
123
+ logger .Infof ("Shutting down server" )
124
+ _ = httpServer .Shutdown (ctx )
125
+ logger .Infof ("Server stopped" )
126
+ close (done )
98
127
})
99
128
100
- if err := server .Serve (listener ); err != nil && ! errors .Is (err , http .ErrServerClosed ) {
129
+ if err = httpServer .Serve (listener ); ! errors .Is (err , http .ErrServerClosed ) {
101
130
return fmt .Errorf ("server error: %w" , err )
102
131
}
103
132
133
+ <- done
104
134
return nil
105
135
}
106
-
107
- func (s * server ) Close () {
108
- s .client .Close (true )
109
- s .events .Close ()
110
- }
0 commit comments