package spartan import ( "bufio" "context" "errors" "fmt" "io" "net" "tildegit.org/tjp/sliderule/internal/types" "tildegit.org/tjp/sliderule/internal" "tildegit.org/tjp/sliderule/logging" ) type spartanServer struct { internal.Server handler types.Handler } func (ss spartanServer) Protocol() string { return "SPARTAN" } // NewServer builds a spartan server. func NewServer( ctx context.Context, hostname string, network string, address string, handler types.Handler, baseLog logging.Logger, ) (types.Server, error) { ss := &spartanServer{handler: handler} hostname = internal.JoinDefaultPort(hostname, "300") address = internal.JoinDefaultPort(address, "300") var err error ss.Server, err = internal.NewServer(ctx, hostname, network, address, baseLog, ss.handleConn) if err != nil { return nil, err } return ss, nil } func (ss *spartanServer) handleConn(conn net.Conn) { buf := bufio.NewReader(conn) var response *types.Response request, clen, err := ParseRequest(buf) if err != nil { response = ClientError(err) } else { request.Server = ss request.RemoteAddr = conn.RemoteAddr() var body io.Reader = nil if clen > 0 { body = io.LimitReader(buf, int64(clen)) } request.Meta = body defer func() { if r := recover(); r != nil { err := fmt.Errorf("%s", r) _ = ss.LogError("msg", "panic in handler", "err", err) rdr := NewResponseReader(ServerError(errors.New("Server error"))) _, _ = io.Copy(conn, rdr) } }() response = ss.handler.Handle(ss.Ctx, request) if response == nil { response = ClientError(errors.New("Resource does not exist.")) } } defer response.Close() _, _ = io.Copy(conn, NewResponseReader(response)) }