eintopf.info@v0.13.16/service/killswitch/transport.go (about)

     1  // Copyright (C) 2022 The Eintopf authors
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    15  
    16  package killswitch
    17  
    18  import (
    19  	"net/http"
    20  	"strings"
    21  
    22  	"github.com/go-chi/chi/v5"
    23  
    24  	"eintopf.info/internal/xhttp"
    25  )
    26  
    27  // Router returns a new killswitch router.
    28  func Router(service Service) func(chi.Router) {
    29  	server := &server{service}
    30  	return func(r chi.Router) {
    31  		r.Options("/turnon", xhttp.CorsHandler)
    32  
    33  		// swagger:route GET /killswitch/turnon/{hash} killswitch kill
    34  		//
    35  		// Sets the internal state to on, provided a valid hash was provided.
    36  		//
    37  		//     Responses:
    38  		//       200: loginSuccess
    39  		//       400: badRequest
    40  		//       500: internalError
    41  		r.Get("/turnon/{hash}", server.turnOn)
    42  
    43  		r.Options("/turnoff", xhttp.CorsHandler)
    44  
    45  		// swagger:route GET /killswitch/turnoff/{hash} killswitch resurrect
    46  		//
    47  		// Sets the internal state to off, provided the hash is valid
    48  		// When the state is off, the server will respond with a 503 status
    49  		// code.
    50  		//
    51  		//
    52  		//     Responses:
    53  		//       200: loginSuccess
    54  		//       400: badRequest
    55  		//       500: internalError
    56  		//       503: serviceUnavailable
    57  		r.Get("/turnoff/{hash}", server.turnOff)
    58  	}
    59  }
    60  
    61  type server struct {
    62  	service Service
    63  }
    64  
    65  func (s *server) turnOn(w http.ResponseWriter, r *http.Request) {
    66  	hash := chi.URLParam(r, "hash")
    67  	err := s.service.TurnOn(r.Context(), hash)
    68  	if err != nil {
    69  		xhttp.WriteError(r.Context(), w, err)
    70  		return
    71  	}
    72  	w.Write([]byte{})
    73  }
    74  
    75  func (s *server) turnOff(w http.ResponseWriter, r *http.Request) {
    76  	hash := chi.URLParam(r, "hash")
    77  	err := s.service.TurnOff(r.Context(), hash)
    78  	if err != nil {
    79  		xhttp.WriteError(r.Context(), w, err)
    80  		return
    81  	}
    82  	w.Write([]byte{})
    83  }
    84  
    85  // Middleware returns a new killswitch middleware.
    86  // It checks wether the state is on. If not it writes a 503 response.
    87  func Middleware(service Service) func(next http.Handler) http.Handler {
    88  	return func(next http.Handler) http.Handler {
    89  		fn := func(w http.ResponseWriter, r *http.Request) {
    90  			on, err := service.On(r.Context())
    91  			if err != nil {
    92  				xhttp.WriteInternalError(r.Context(), w, err)
    93  			}
    94  			if !on && !strings.Contains(r.RequestURI, "turnon") {
    95  				// Cancel the request when the state is off and the
    96  				// turnon endpoint wasn't called.
    97  				xhttp.WriteServiceUnavailable(w)
    98  				return
    99  			}
   100  			next.ServeHTTP(w, r)
   101  		}
   102  		return http.HandlerFunc(fn)
   103  	}
   104  }