@@ -44,7 +44,25 @@ var authenticationRedirectHTML string
4444
4545var tmpl * template.Template
4646
47- var localClient tailscale.LocalClient
47+ // Server is the backend server for a Tailscale web client.
48+ type Server struct {
49+ devMode bool
50+ lc * tailscale.LocalClient
51+ }
52+
53+ // NewServer constructs a new Tailscale web client server.
54+ //
55+ // lc is an optional parameter. When not filled, NewServer
56+ // initializes its own tailscale.LocalClient.
57+ func NewServer (devMode bool , lc * tailscale.LocalClient ) * Server {
58+ if lc == nil {
59+ lc = & tailscale.LocalClient {}
60+ }
61+ return & Server {
62+ devMode : devMode ,
63+ lc : lc ,
64+ }
65+ }
4866
4967func init () {
5068 tmpl = template .Must (template .New ("web.html" ).Parse (webHTML ))
@@ -264,8 +282,8 @@ req.send(null);
264282</body></html>
265283`
266284
267- // Handle processes all requests for the Tailscale web client.
268- func Handle (w http.ResponseWriter , r * http.Request ) {
285+ // ServeHTTP processes all requests for the Tailscale web client.
286+ func ( s * Server ) ServeHTTP (w http.ResponseWriter , r * http.Request ) {
269287 ctx := r .Context ()
270288 if authRedirect (w , r ) {
271289 return
@@ -281,12 +299,12 @@ func Handle(w http.ResponseWriter, r *http.Request) {
281299 return
282300 }
283301
284- st , err := localClient .StatusWithoutPeers (ctx )
302+ st , err := s . lc .StatusWithoutPeers (ctx )
285303 if err != nil {
286304 http .Error (w , err .Error (), http .StatusInternalServerError )
287305 return
288306 }
289- prefs , err := localClient .GetPrefs (ctx )
307+ prefs , err := s . lc .GetPrefs (ctx )
290308 if err != nil {
291309 http .Error (w , err .Error (), http .StatusInternalServerError )
292310 return
@@ -316,7 +334,7 @@ func Handle(w http.ResponseWriter, r *http.Request) {
316334 mp .Prefs .AdvertiseRoutes = routes
317335 log .Printf ("Doing edit: %v" , mp .Pretty ())
318336
319- if _ , err := localClient .EditPrefs (ctx , mp ); err != nil {
337+ if _ , err := s . lc .EditPrefs (ctx , mp ); err != nil {
320338 w .WriteHeader (http .StatusInternalServerError )
321339 json .NewEncoder (w ).Encode (mi {"error" : err .Error ()})
322340 return
@@ -331,7 +349,7 @@ func Handle(w http.ResponseWriter, r *http.Request) {
331349 logout = true
332350 }
333351 log .Printf ("tailscaleUp(reauth=%v, logout=%v) ..." , reauth , logout )
334- url , err := tailscaleUp (r .Context (), st , postData )
352+ url , err := s . tailscaleUp (r .Context (), st , postData )
335353 log .Printf ("tailscaleUp = (URL %v, %v)" , url != "" , err )
336354 if err != nil {
337355 w .WriteHeader (http .StatusInternalServerError )
@@ -386,9 +404,9 @@ func Handle(w http.ResponseWriter, r *http.Request) {
386404 w .Write (buf .Bytes ())
387405}
388406
389- func tailscaleUp (ctx context.Context , st * ipnstate.Status , postData postedData ) (authURL string , retErr error ) {
407+ func ( s * Server ) tailscaleUp (ctx context.Context , st * ipnstate.Status , postData postedData ) (authURL string , retErr error ) {
390408 if postData .ForceLogout {
391- if err := localClient .Logout (ctx ); err != nil {
409+ if err := s . lc .Logout (ctx ); err != nil {
392410 return "" , fmt .Errorf ("Logout error: %w" , err )
393411 }
394412 return "" , nil
@@ -415,18 +433,18 @@ func tailscaleUp(ctx context.Context, st *ipnstate.Status, postData postedData)
415433
416434 watchCtx , cancelWatch := context .WithCancel (ctx )
417435 defer cancelWatch ()
418- watcher , err := localClient .WatchIPNBus (watchCtx , 0 )
436+ watcher , err := s . lc .WatchIPNBus (watchCtx , 0 )
419437 if err != nil {
420438 return "" , err
421439 }
422440 defer watcher .Close ()
423441
424442 go func () {
425443 if ! isRunning {
426- localClient .Start (ctx , ipn.Options {})
444+ s . lc .Start (ctx , ipn.Options {})
427445 }
428446 if forceReauth {
429- localClient .StartLoginInteractive (ctx )
447+ s . lc .StartLoginInteractive (ctx )
430448 }
431449 }()
432450
0 commit comments