@ -1,122 +1,2 @@
// Package gmi implements the gemini-based api for the mediocre-blog.
// Package gmi contains utilities for working with gemini and gemtext
package gmi
import (
"context"
"errors"
"fmt"
"net/url"
"os"
"strings"
"git.sr.ht/~adnano/go-gemini"
"git.sr.ht/~adnano/go-gemini/certificate"
"github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
"github.com/mediocregopher/mediocre-go-lib/v2/mctx"
"github.com/mediocregopher/mediocre-go-lib/v2/mlog"
)
// Params are used to instantiate a new API instance. All fields are required
// unless otherwise noted.
type Params struct {
Logger * mlog . Logger
PublicURL * url . URL
ListenAddr string
CertificatesPath string
}
// SetupCfg implement the cfg.Cfger interface.
func ( p * Params ) SetupCfg ( cfg * cfg . Cfg ) {
publicURLStr := cfg . String ( "gemini-public-url" , "gemini://localhost:2065" , "URL this service is accessible at" )
cfg . StringVar ( & p . ListenAddr , "gemini-listen-addr" , ":2065" , "Address to listen for HTTP requests on" )
cfg . StringVar ( & p . CertificatesPath , "gemini-certificates-path" , "" , "Path to directory where gemini certs should be created/stored" )
cfg . OnInit ( func ( context . Context ) error {
if p . CertificatesPath == "" {
return errors . New ( "-gemini-certificates-path is required" )
}
var err error
* publicURLStr = strings . TrimSuffix ( * publicURLStr , "/" )
if p . PublicURL , err = url . Parse ( * publicURLStr ) ; err != nil {
return fmt . Errorf ( "parsing -gemini-public-url: %w" , err )
}
return nil
} )
}
// Annotate implements mctx.Annotator interface.
func ( p * Params ) Annotate ( a mctx . Annotations ) {
a [ "geminiPublicURL" ] = p . PublicURL
a [ "geminiListenAddr" ] = p . ListenAddr
a [ "geminiCertificatesPath" ] = p . CertificatesPath
}
// API will listen on the port configured for it, and serve gemini requests for
// the mediocre-blog.
type API interface {
Shutdown ( ctx context . Context ) error
}
type api struct {
params Params
srv * gemini . Server
}
// New initializes and returns a new API instance, including setting up all
// listening ports.
func New ( params Params ) ( API , error ) {
if err := os . MkdirAll ( params . CertificatesPath , 0700 ) ; err != nil {
return nil , fmt . Errorf ( "creating certificate directory %q: %w" , params . CertificatesPath , err )
}
certStore := new ( certificate . Store )
certStore . Load ( params . CertificatesPath )
certStore . Register ( params . PublicURL . Hostname ( ) )
a := & api {
params : params ,
}
a . srv = & gemini . Server {
Addr : params . ListenAddr ,
Handler : a . handler ( ) ,
GetCertificate : certStore . Get ,
}
go func ( ) {
ctx := mctx . WithAnnotator ( context . Background ( ) , & a . params )
err := a . srv . ListenAndServe ( ctx )
if err != nil && ! errors . Is ( err , context . Canceled ) {
a . params . Logger . Fatal ( ctx , "serving gemini server" , err )
}
} ( )
return a , nil
}
func ( a * api ) Shutdown ( ctx context . Context ) error {
return a . srv . Shutdown ( ctx )
}
func ( a * api ) handler ( ) gemini . Handler {
return gemini . HandlerFunc ( func (
ctx context . Context ,
rw gemini . ResponseWriter ,
r * gemini . Request ,
) {
fmt . Fprintf ( rw , "# Test\n\n" )
fmt . Fprintf ( rw , "HELLO WORLD\n\n" )
fmt . Fprintf ( rw , "=> gemini://midnight.pub Hit the pub\n\n" )
} )
}