Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Derive whosonfirst.spelunker.uris.js at runtime #38

Merged
merged 2 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 24 additions & 0 deletions app/server/handlers_www.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/sfomuseum/go-http-opensearch"
opensearch_http "github.com/sfomuseum/go-http-opensearch/http"
"github.com/whosonfirst/go-whosonfirst-spelunker-httpd/templates/javascript"
"github.com/whosonfirst/go-whosonfirst-spelunker-httpd/www"
)

Expand All @@ -19,6 +20,29 @@ func staticHandlerFunc(ctx context.Context) (http.Handler, error) {
return http.StripPrefix(run_options.URIs.Static, fs_handler), nil
}

func urisJSHandlerFunc(ctx context.Context) (http.Handler, error) {

setupWWWOnce.Do(setupWWW)

if setupWWWError != nil {
slog.Error("Failed to set up common configuration", "error", setupWWWError)
return nil, fmt.Errorf("Failed to set up common configuration, %w", setupWWWError)
}

js_templates, err := javascript.LoadTemplates(ctx)

if err != nil {
return nil, fmt.Errorf("Failed to load JavaScript templates, %w", err)
}

opts := &www.URIsJSHandlerOptions{
Templates: js_templates,
URIs: uris_table,
}

return www.URIsJSHandler(opts)
}

func openSearchHandlerFunc(ctx context.Context) (http.Handler, error) {

setupWWWOnce.Do(setupWWW)
Expand Down
2 changes: 1 addition & 1 deletion app/server/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func RunOptionsFromFlagSet(ctx context.Context, fs *flag.FlagSet) (*RunOptions,
}

uris_table = httpd.DefaultURIs()
uris_table.Root = root_u
uris_table.RootURL = root_u.String()

t_funcs := html_template.FuncMap{
"IsAvailable": sfom_funcs.IsAvailable,
Expand Down
9 changes: 9 additions & 0 deletions app/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"log/slog"
"net/http"
"net/url"

"github.com/aaronland/go-http-server"
"github.com/aaronland/go-http-server/handler"
Expand Down Expand Up @@ -47,6 +48,12 @@ func RunWithOptions(ctx context.Context, opts *RunOptions, logger *slog.Logger)
// START OF defer loading handlers (and all their dependencies) until they are actually routed to
// in case we are running in a "serverless" environment like AWS Lambda

path_urisjs, err := url.JoinPath(run_options.URIs.Static, "/javascript/whosonfirst.spelunker.uris.js")

if err != nil {
return fmt.Errorf("Failed to construct path for whosonfirst.spelunker.uris.js, %w", err)
}

handlers := map[string]handler.RouteHandlerFunc{

// WWW/human-readable
Expand All @@ -70,6 +77,8 @@ func RunWithOptions(ctx context.Context, opts *RunOptions, logger *slog.Logger)

// Static assets
run_options.URIs.Static: staticHandlerFunc,
// Run-time static assets
path_urisjs: urisJSHandlerFunc,

// API/machine-readable
run_options.URIs.ConcordanceNSFaceted: hasConcordanceFacetedHandlerFunc,
Expand Down
13 changes: 0 additions & 13 deletions static/javascript/whosonfirst.spelunker.uris.js

This file was deleted.

29 changes: 29 additions & 0 deletions templates/javascript/whosonfirst.spelunker.uris.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{{ define "whosonfirst_spelunker_uris" -}}
var whosonfirst = whosonfirst || {};
whosonfirst.spelunker = whosonfirst.spelunker || {};

whosonfirst.spelunker.uris = (function(){

var _table = {{ .Table }};

var self = {

abs_root_url: function(){

var root = _table.root_url;

if (! root.endsWith("/")){
root += "/";
}

return root;
},

table: function(){
return _table;
},
};

return self;
})();
{{ end -}}
18 changes: 10 additions & 8 deletions uris.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ type URIs struct {
SVG string `json:"svg"`
SVGAlt []string `json:"svg_alt"`

Root *url.URL
RootURL string `json:"root_url"`
}

func (u *URIs) ApplyPrefix(prefix string) error {
Expand Down Expand Up @@ -170,16 +170,18 @@ func DefaultURIs() *URIs {

func (uris_table *URIs) Abs(path string) (string, error) {

if uris_table.Root == nil {
return "#", fmt.Errorf("Root URL has not been assigned")
root_u, err := url.Parse(uris_table.RootURL)

if err != nil {
return "", fmt.Errorf("Failed to parse root URL, %w", err)
}

u := url.URL{}
u.Host = uris_table.Root.Host
u.Scheme = uris_table.Root.Scheme
u.Path = path
this_u := url.URL{}
this_u.Host = root_u.Host
this_u.Scheme = root_u.Scheme
this_u.Path = path

return u.String(), nil
return this_u.String(), nil
}

func URIForIdSimple(uri string, id int64) string {
Expand Down
60 changes: 60 additions & 0 deletions www/uris.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package www

import (
"encoding/json"
"fmt"
"log/slog"
"net/http"
"text/template"

"github.com/whosonfirst/go-whosonfirst-spelunker-httpd"
)

type URIsJSHandlerOptions struct {
Templates *template.Template
URIs *httpd.URIs
}

type URIsJSVars struct {
Table string
}

func URIsJSHandler(opts *URIsJSHandlerOptions) (http.Handler, error) {

t := opts.Templates.Lookup("whosonfirst_spelunker_uris")

if t == nil {
return nil, fmt.Errorf("Failed to locate 'whosonfirst_spelunker_uris' template")
}

fn := func(rsp http.ResponseWriter, req *http.Request) {

logger := slog.Default()
logger = logger.With("request", req.URL)

enc_table, err := json.Marshal(opts.URIs)

if err != nil {
logger.Error("Failed to marshal URIs table", "error", err)
http.Error(rsp, "Internal server error", http.StatusInternalServerError)
return
}

vars := URIsJSVars{
Table: string(enc_table),
}

rsp.Header().Set("Content-type", "text/javascript")
err = t.Execute(rsp, vars)

if err != nil {
logger.Error("Failed to execute template", "error", err)
http.Error(rsp, "Internal server error", http.StatusInternalServerError)
return
}

return
}

return http.HandlerFunc(fn), nil
}