From 66a1b1f39a1e1d5499b548b36d18c8daa872d7da Mon Sep 17 00:00:00 2001 From: tjpcc Date: Sat, 28 Jan 2023 14:52:35 -0700 Subject: gopher support. Some of the contrib packages were originally built gemini-specific and had to be refactored into generic core functionality and thin protocol-specific wrappers for each of gemini and gopher. --- gopher/serve.go | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 gopher/serve.go (limited to 'gopher/serve.go') diff --git a/gopher/serve.go b/gopher/serve.go new file mode 100644 index 0000000..84745d7 --- /dev/null +++ b/gopher/serve.go @@ -0,0 +1,72 @@ +package gopher + +import ( + "context" + "errors" + "fmt" + "io" + "net" + "strings" + + "tildegit.org/tjp/gus" + "tildegit.org/tjp/gus/internal" + "tildegit.org/tjp/gus/logging" +) + +type gopherServer struct { + internal.Server + handler gus.Handler +} + +func (gs gopherServer) Protocol() string { return "GOPHER" } + +// NewServer builds a gopher server. +func NewServer( + ctx context.Context, + hostname string, + network string, + address string, + handler gus.Handler, + errLog logging.Logger, +) (gus.Server, error) { + gs := &gopherServer{handler: handler} + + if strings.IndexByte(hostname, ':') < 0 { + hostname = net.JoinHostPort(hostname, "70") + } + + var err error + gs.Server, err = internal.NewServer(ctx, hostname, network, address, errLog, gs.handleConn) + if err != nil { + return nil, err + } + + return gs, nil +} + +func (gs *gopherServer) handleConn(conn net.Conn) { + var response *gus.Response + request, err := ParseRequest(conn) + if err != nil { + response = Error(errors.New("Malformed request.")).Response() + } else { + request.Server = gs + request.RemoteAddr = conn.RemoteAddr() + + defer func() { + if r := recover(); r != nil { + err := fmt.Errorf("%s", r) + _ = gs.LogError("msg", "panic in handler", "err", err) + rdr := NewResponseReader(Error(errors.New("Server error.")).Response()) + _, _ = io.Copy(conn, rdr) + } + }() + response = gs.handler(gs.Ctx, request) + if response == nil { + response = Error(errors.New("Resource does not exist.")).Response() + } + } + + defer response.Close() + _, _ = io.Copy(conn, NewResponseReader(response)) +} -- cgit v1.2.3