antennaApp

package module
v0.0.20 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 25, 2025 License: AGPL-3.0 Imports: 43 Imported by: 0

README

Antenna App

antenna is a command line feed oriented content management tool. It let's you create and curate simple website, micro blogs, blogs, link blogs, and person news sites using Markdown. It was inspired by Dave Winer's Textcasting concept, FeedLand and my own experimental website, antenna. The goal of the Antenna App is to make it easy for writers create web sites without being required to be web developers or software engineers.

Antenna App's Features:

  • Pages and posts are written using Markdown
  • Posts are automatically included in an RSS feed for your site
  • Aggregations of feeds can be included by providing Markdown list of links to RSS, Atom and JSON feeds
  • Pages, posts and aggregations can include metadata expressed as YAML front matter[^1]
  • Posts can be added to curated feed collection too
  • You can have multiple collections of feeds
  • Collections can be harvested individually or collectively
  • The managed content is stored in SQLite3 database(s)
  • HTML, RSS 2.0, OPML and sitemap.xml documents are automatically generated without additional configuration
    • HTML files are generated for each post, page and aggregation collection
  • A preview feature to view the render content in your web browser via a localhost URL
  • Site customization is possible through the use of page generators
    • Page generators YAML files describing basic elements of a page, header, navigation, before/after content section, footer
    • Custom page generators are composed by apply "themes"
    • Themes are a directory populated with Markdown files describing each element of the theme[^2]
    • Page generators are implemented as a YAML file, they are used to frame the Markdown content added a pages and posts
    • Each collection may contain its own page generator
  • Antenna App plays well with other static website tools (e.g. PageFind)

[^1]: YAML is a simple notation describing structed data. Front matter is a block of text hodling metadata about the document. Using YAML Front Matter is a common practice in the Markdown community. I first encountered it in the data science community and other scholarly science communities.

[^2]: A YAML file called head.yaml is used to describe custom meta, link and script elements in the page. There is a style.css file that can be included in a theme to be included in the head element of rendered HTML.

The combined features of Antenna App go beyond most static site generators. It provides a means of making collaboritive website through the ability to import feeds from one or more people. You can add your own Markdown content to a feed allowing for commentary in a specific feed collection. Feed orientation allows Antenna App sites to be social without turning over atonomy of our content to another site.

I believe Antenna App is well suited for creating local community sites where each contributed produces a feed of articles that are then linked from a common website. This could be used for aggregating content of special interest groups or for local neighborhood news sites. The site doing the aggregation can control those feed items to be published allowing for editorial control. Since this runs on your computer you don't need to run specialized services hosted on the public web. You get the flexibity of a dynamic system with the low overhead and high availability provided by static websites.

Authors
  • Doiel, R. S. DoielHelpful if you are developing the Antenna App.

Software Requirements

To run Antenna App you just need to install it on a Raspberry Pi, Linux, macOS or Windows computer.

Requirements top compile the Antenna App from source code.

  • Go >= 1.25.3
  • CMTools >= 0.0.40
Software Suggestions

The following are helpful if you want to develop or customize the Antenna App software.

  • GNU Make >= 3.4
  • Pandoc >= 3.1
  • Bash or Powershell

Documentation

Overview

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

Index

Constants

View Source
const (
	// Version number of release
	Version = "0.0.20"

	// ReleaseDate, the date version.go was generated
	ReleaseDate = "2025-12-24"

	// ReleaseHash, the Git hash when version.go was generated
	ReleaseHash = "13763d0"
	LicenseText = `` /* 34525-byte string literal not displayed */

)

Variables

View Source
var (
	HelpText = `` /* 10598-byte string literal not displayed */

	ThemeHelpText = `` /* 4766-byte string literal not displayed */

)
View Source
var (
	DefaultPageCollectionMarkdown = `` /* 140-byte string literal not displayed */

	DefaultGeneratorYaml = `` /* 830-byte string literal not displayed */

)
View Source
var (
	// SQLCreateTables provides the statements that are use to create our tables
	// It has two percent s, first is feed list name, second is datetime scheme
	// was generated.
	//
	// See <https://source.scripting.com> when I am ready to support more the
	// source namespace.
	SQLCreateTables = `` /* 774-byte string literal not displayed */

	// SQLResetChannels clear the channels table
	SQLResetChannels = `DELETE FROM channels;`

	// Update the channels table
	SQLUpdateChannel = `` /* 221-byte string literal not displayed */

	// Display the channels in the table
	SQLDisplayChannels = `` /* 186-byte string literal not displayed */

	// Update a feed item in the items table
	SQLUpdateItem = `` /* 457-byte string literal not displayed */

	// SQLItemCount returns a list of items in the items table
	SQLItemCount = `SELECT COUNT(*) FROM items;`

	// SQLDisplayItems returns a list of items in decending chronological order.
	SQLDisplayItems = `` /* 285-byte string literal not displayed */

	// SQLRssPosts generate an RSS feed for all posts
	SQLRssPosts = `` /* 279-byte string literal not displayed */

	// SQLRssRecentPosts generate an RSS feed for recent posts
	SQLRssRecentPosts = `` /* 288-byte string literal not displayed */

	// SQLRssDateRangePosts generate an RSS feed for recent posts
	SQLRssDateRangePosts = `` /* 306-byte string literal not displayed */

	// SQLListPosts will list all published posts with a postPath by their descending pubDate
	SQLListPosts = `` /* 147-byte string literal not displayed */

	// SQLListRecentPosts will list recent published posts with a postPath by their descending pubDate
	SQLListRecentPosts = `` /* 155-byte string literal not displayed */

	// SQLListDateRangePosts will list all published posts with a postPath by their descending pubDate
	SQLListDateRangePosts = `` /* 168-byte string literal not displayed */

	// SQLSetStatusToReview
	SQLUpdateStatusToReview = `UPDATE items SET status = 'review';`

	// SQLSetStatusPublishedForRecentlyPublished will the will set status to "published" where
	// Items have a published date greater than or equal to the date provided.
	SQLSetStatusPublishedForRecentlyPublished = `UPDATE items SET status = 'published' WHERE pubDate >= date('now', '-21 days');`

	// SQLDeleteItemByLinkOrPostPath removes an item in the items table with provided link
	SQLDeleteItemByLinkOrPostPath = `DELETE FROM items WHERE link = ? OR postPath = ?`

	// SQLSetItemStatus is used when curating items in collections
	SQLSetItemStatus = `UPDATE items SET status = ?
WHERE link = ?`

	// Update a feed item in the items table
	SQLUpdatePage = `` /* 151-byte string literal not displayed */

	// SQLCountPage returns a list of items in the items table
	SQLCountPage = `SELECT COUNT(*) FROM pages;`

	// SQLDisplayPage returns a list of pages in the pages table
	SQLDisplayPage = `SELECT inputPath, outputPath, updated
FROM pages
ORDER BY updated desc
;`

	// SQLSitemapListPages returns a list of pages by outputPath
	SQLSitemapListPages = `SELECT outputPath, updated
FROM pages
ORDER BY outputPath
;`

	// SQLListPosts will list all posts by post path
	SQLSitemapListPosts = `` /* 215-byte string literal not displayed */

	// SQLDeletePageByPath removes a page by either input or output paths.
	SQLDeletePageByPath = `DELETE
FROM pages
WHERE inputPath = ?1 or outputPath = ?2
;`

	// SQLListRecentItems will list recent Itemsby their descending pubDate
	SQLListRecentItems = `` /* 142-byte string literal not displayed */

	// SQLListDateRangeItems will list items in date range by their descending pubDate
	SQLListDateRangeItems = `` /* 180-byte string literal not displayed */

	// SQLListItems will list all items by their descending pubDate
	SQLListItems = `` /* 134-byte string literal not displayed */

	// SQLViewItem returns a single item
	SQLViewItem = `` /* 127-byte string literal not displayed */

)

Functions

func AccessHandler

func AccessHandler(next http.Handler, a *Access) http.Handler

AccessHandler is a wrapping handler that checks if Access.Routes matches the req.URL.Path and if so applies access contraints. If *Access is nil then it just passes through to the next handler.

func CheckWaitInterval

func CheckWaitInterval(iTime time.Time, wait time.Duration) (time.Time, bool)

CheckWaitInterval checks to see if an interval of time has been met or exceeded. It returns the remaining time interval (possibly reset) and a boolean. The boolean is true when the time interval has been met or exceeded, false otherwise.

``` tot := len(something) // calculate the total number of items to process t0 := time.Now() iTime := time.Now() reportProgress := false

for i, key := range records {
    // ... process stuff ...
    if iTime, reportProgress = checkWaitInterval(rptTime, (30 * time.Second)); reportProgress {
        log.Printf("%s", ProgressETA(t0, i, tot))
    }
}

```

func FmtHelp

func FmtHelp(src string, appName string, version string, releaseDate string, releaseHash string) string

FmtHelp lets you process a text block with simple curly brace markup.

func IncludeCodeBlock added in v0.0.15

func IncludeCodeBlock(text string) string

IncludeCodeBlock takes a text string and replaces the code blocks based on the file path included in the line and the language name. The generated code block uses the `~~~` sequence to delimit the block with the language name provided in the opening delimiter.

Parameters:

text (string): the text to be transformed

Returns:

string: the transformed text

func IncludeTextBlock added in v0.0.15

func IncludeTextBlock(text string) string

IncludeTextBlock takes a text string and replaces the text blocks based on the file path included in the line.

Parameters:

text (string): the text to be transformed

Returns:

string: the transformed text

func InitPageGenerator added in v0.0.8

func InitPageGenerator(pageName string) error

InitPageGenerator initializes a YAML configuration for the default page layout. It takes a filename and returns an error

func IsDotPath

func IsDotPath(p string) bool

IsDotPath checks to see if a path is requested with a dot file (e.g. docs/.git/* or docs/.htaccess)

func JSONMarshal

func JSONMarshal(data interface{}) ([]byte, error)

JSONMarshal provides provide a custom json encoder to solve a an issue with HTML entities getting converted to UTF-8 code points by json.Marshal(), json.MarshalIndent().

func JSONMarshalIndent

func JSONMarshalIndent(data interface{}, prefix string, indent string) ([]byte, error)

JSONMarshalIndent provides provide a custom json encoder to solve a an issue with HTML entities getting converted to UTF-8 code points by json.Marshal(), json.MarshalIndent().

func JSONUnmarshal

func JSONUnmarshal(src []byte, data interface{}) error

JSONUnmarshal is a custom JSON decoder so we can treat numbers easier

func LoadRedirects

func LoadRedirects(fName string) (map[string]string, error)

LoadRedirects reads a CSV file of redirects and returns a map[string]string of from/to static rediects.

func ProgressETA

func ProgressETA(t0 time.Time, i int, tot int) string

ProgressETA returns a string with the percentage processed and estimated time remaining. It requires the a counter of records processed, the total count of records and a time zero value.

``` tot := len(something) // calculate the total number of items to process t0 := time.Now() iTime := time.Now() reportProgress := false

for i, key := range records {
    // ... process stuff ...
    if iTime, reportProgress = CheckWaitInterval(rptTime, (30 * time.Second)); reportProgress {
        log.Printf("%s", ProgressETA(t0, i, tot))
    }
}

```

func ProgressIPS

func ProgressIPS(t0 time.Time, i int, timeUnit time.Duration) string

ProgressIPS returns a string with the elapsed time and increments per second. Takes a time zero, a counter and time unit. Returns a string with count, running time and increments per time unit. ``` t0 := time.Now() iTime := time.Now() reportProgress := false

for i, key := range records {
    // ... process stuff ...
    if iTime, reportProgress = CheckWaitInterval(rptTime, (30 * time.Second)); reportProgress || i = 0 {
        log.Printf("%s", ProgressIPS(t0, i, time.Second))
    }
}

```

func RequestLogger

func RequestLogger(next http.Handler) http.Handler

RequestLogger logs the request based on the request object passed into it.

func ResponseLogger

func ResponseLogger(r *http.Request, status int, err error)

ResponseLogger logs the response based on a request, status and error message

func SplitFrontMatter

func SplitFrontMatter(src []byte) (map[string]interface{}, string, error)

SplitFrontMatter splits a CommonMark document into FrontMatter and the rest of the content. It uses bufio.ScanLines to find the "---" delimiters.

func StaticRouter

func StaticRouter(next http.Handler) http.Handler

StaticRouter scans the request object to either add a .html extension or prevent serving a dot file path

Types

type Access

type Access struct {
	// AuthType (e.g. Basic)
	AuthType string `json:"auth_type" yaml:"auth_type"`
	// AuthName (e.g. string describing authorization, e.g. realm in basic auth)
	AuthName string `json:"auth_name" yaml:"auth_name"`
	// Encryption is a string describing the encryption used
	// e.g. argon2id, pbkds2, md5 or sha512
	Encryption string `json:"encryption" yaml:"encryption"`
	// Map holds a user to secret map. It is usually populated
	// after reading in the users file with LoadAccessYAML() or
	// LoadAccessJSON().
	Map map[string]*Secrets `json:"access" yaml:"access"`
	// Routes is a list of URL path prefixes covered by
	// this Access control object.
	Routes []string `json:"routes" yaml:"routes"`
}

Access holds the necessary configuration for doing basic auth authentication. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication using Go's http.Request object.

func LoadAccess

func LoadAccess(fName string) (*Access, error)

LoadAccess loads a YAML or JSON access file.

func (*Access) DumpAccess

func (a *Access) DumpAccess(fName string) error

DumpAccess writes a access file.

func (*Access) GetUsername

func (a *Access) GetUsername(r *http.Request) (string, error)

GetUsername takes an Request object, inspects the headers and returns the username if possible, otherwise an error.

func (*Access) Handler

func (a *Access) Handler(next http.Handler) http.Handler

Handler takes a handler and returns handler. If *Access is null it pass thru unchanged. Otherwise it applies the access policy.

func (*Access) Login

func (a *Access) Login(username string, password string) bool

Login accepts username, password and ok boolean. Returns true if they match auth's settings false otherwise.

How to choosing an appropriate hash method see

https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html

md5 and sha512 are included for historic reasons They are NOT considered secure anymore as they are breakable with brute force using today's CPU/GPUs.

func (*Access) RemoveAccess

func (a *Access) RemoveAccess(username string) bool

RemoveAccess takes an *Access and username and deletes the username from .Map returns true if delete applied, false if user not found in map

func (*Access) UpdateAccess

func (a *Access) UpdateAccess(username string, password string) bool

UpdateAccess uses an *Access and username, password generates a salt and then adds username, salt and secret to .Map (creating one if needed)

type AntennaApp

type AntennaApp struct {
	// contains filtered or unexported fields
}

func NewAntennaApp

func NewAntennaApp(appName string) *AntennaApp

func (*AntennaApp) Add

func (app *AntennaApp) Add(cfgName string, args []string) error

func (AntennaApp) ApplyTheme added in v0.0.11

func (app AntennaApp) ApplyTheme(cfgName string, args []string) error

ApplyTheme takes a theme directory and an optional generator YAML filename and applies the theme to that generator YAML name saving the result.

func (*AntennaApp) Curate added in v0.0.20

func (app *AntennaApp) Curate(cfgName string, args []string) error

Curate provides a simple terminal interface to curating collections and feed items for publication in your Antenna site.

func (*AntennaApp) Del

func (app *AntennaApp) Del(cfgName string, args []string) error

Del removes one or more collections from your Antenna instance. NOTE: It does not remove generated files, e.g. SQLite3 database, YAML, HTML or RSS files.

func (AntennaApp) Generate

func (app AntennaApp) Generate(out io.Writer, eout io.Writer, cfgName string, args []string) error

func (AntennaApp) Harvest

func (app AntennaApp) Harvest(out io.Writer, eout io.Writer, cfgName string, args []string) error

func (*AntennaApp) Init

func (app *AntennaApp) Init(cfgName string, args []string) error

func (*AntennaApp) Page added in v0.0.7

func (app *AntennaApp) Page(cfgName string, args []string) error

Page will add a CommonMark document as an HTML page based on postPath. It **will not** get added to an RSS feed or to the collection's db. It is designed to relieve the requirement of using Pandoc for a handful of page.

func (*AntennaApp) Pages added in v0.0.16

func (app *AntennaApp) Pages(cfgName string, args []string) error

Pages will list the pages in the pages collection

func (*AntennaApp) Post

func (app *AntennaApp) Post(cfgName string, args []string) error

Post will add a CommonMark document as a feed item and if the postPath and link are provided it will convert the CommonMark document to HTML and save it in the postPath.

func (*AntennaApp) Posts added in v0.0.18

func (app *AntennaApp) Posts(cfgName string, args []string) error

func (*AntennaApp) Preview

func (app *AntennaApp) Preview(cfgName string) error

Preview runs a webserver that will preview the AntennaApp instance's htdocs on the port specified in the config.

func (*AntennaApp) QuoteTextFragment added in v0.0.19

func (app *AntennaApp) QuoteTextFragment(out io.Writer, cfgName string, args []string) error

QuoteTextFragment takes a text fragment URL and writes a Markdown text from it to standard output.

func (*AntennaApp) RssPosts added in v0.0.19

func (app *AntennaApp) RssPosts(cfgName string, args []string) error

RssPosts, gernate RSS to stdout for posts

func (*AntennaApp) Run

func (app *AntennaApp) Run(in io.Reader, out io.Writer, eout io.Writer, cfgName string, action string, args []string) error

Run implements the command line functionality of the Antenna App.

func (*AntennaApp) Sitemap added in v0.0.16

func (app *AntennaApp) Sitemap(cfgName string, args []string) error

Sitemap implements the antenna sitemap action.

func (*AntennaApp) Unpage added in v0.0.16

func (app *AntennaApp) Unpage(cfgName string, args []string) error

Unpage will remove a CommonMark document filePath

func (*AntennaApp) Unpost

func (app *AntennaApp) Unpost(cfgName string, args []string) error

type AppConfig

type AppConfig struct {
	// Port holds the port number the preview web service will run on
	Port int `json:"port,omitempty" yaml:"port,omitempty"`

	// Host holds the IP address or machine name the preview service
	// will listen on. By default is is "localhost"
	Host string `json:"host,omitempty" yaml:"host,omitempty"`

	// Htdocs holds the path to directory that will recieve the generated content
	// It is also the directory used in the "preview" the static website.
	Htdocs string `json:"htdocs,omitempty" yaml:"htdocs,omitempty"`

	// UserAgent this holds a custom user agent string
	UserAgent string `json:"userAgent,omitempty" yaml:"userAgent,omitempty"`

	// BaseURL for the Antenna instance
	BaseURL string `json:"base_url,omitempty" yaml:"base_url,omitempty"`

	// Generator holds a YAML file that describes the HTML page structure.
	// This holds the default page generator description. Each collection can
	// use a custom one or the default one.
	Generator string `json:"generator,omitempty" yaml:"generator,omitempty"`

	// Collections holds a list of collections to curate
	Collections []*Collection `json:"collections,omitempty" yaml:"collections,omitempty"`

	// Sitemap settings, these should get sane defaults in the sitemap action
	ChunkSize   int
	DefaultFreq string
	DefaultPri  string
	FreqRules   map[string]string // outputPath prefix -> changefreq
	PriRules    map[string]string // outputPath prefix -> priority

}

AntennaApp configuration structure

func (*AppConfig) AddCollection added in v0.0.20

func (cfg *AppConfig) AddCollection(cfgName string, cName string) error

AddCollection adds and saves a new collection to AppConfig

func (*AppConfig) CollectionIndex

func (cfg *AppConfig) CollectionIndex(cName string) int

func (*AppConfig) DelCollection added in v0.0.20

func (cfg *AppConfig) DelCollection(cfgName string, cName string) error

DelCollection removes a collection from the configuration, saving it.

func (*AppConfig) GetCollection

func (cfg *AppConfig) GetCollection(cName string) (*Collection, error)

func (*AppConfig) LoadConfig

func (cfg *AppConfig) LoadConfig(cfgName string) error

LoadConfig process the AntennaApp YAML file and sets the attributes of the AntennaApp structure.

func (*AppConfig) SaveConfig

func (cfg *AppConfig) SaveConfig(cfgName string) error

SaveConfig save the current configuration of the AntennaApp

type CORSPolicy

type CORSPolicy struct {
	// Origin usually would be set the hostname of the service.
	Origin string `json:"origin,omitempty" yaml:"origin,omitempty"`
	// Options to include in the policy (e.g. GET, POST)
	Options []string `json:"options,omitempty" yaml:"options,omitempty"`
	// Headers to include in the policy
	Headers []string `json:"headers,omitempty" yaml:"headers,omitempty"`
	// ExposedHeaders to include in the policy
	ExposedHeaders []string `json:"exposed_headers,omitempty" yaml:"exposed_headers,omitempty"`
	// AllowCredentials header handling in the policy either true or not set
	AllowCredentials bool `json:"allow_credentials,omitempty" yaml:"allow_credentials,omitempty"`
}

CORSPolicy defines the policy elements for our CORS settings.

func (*CORSPolicy) Handler

func (cors *CORSPolicy) Handler(next http.Handler) http.Handler

Handler accepts an http.Handler and returns a http.Handler. It Wraps the response with the CORS headers based on configuration in CORSPolicy struct. If cors is nil then it passes thru to next http.Handler unaltered.

type Collection

type Collection struct {
	// Title of the collection
	Title string `json:"title,omitempty" yaml:"title,omitempty"`

	// Links holds the Link element used in the published RSS 2.0 output.
	Link string `json:"link,omitempty" yaml:"link,omitempty"`

	// Description holds the description of the collection
	Description string `json:"description,omitempty" yaml:"description,omitempty"`

	// The language the collect is written in
	Language string `json:"language,omitempty" yaml:"language,omitempty"`

	// Copyright notice for content in the collection
	Copyright string `json:"copyright,omitempty" yaml:"copyright,omitempty"`

	// ManagingEditor holds an Email address for person responsible for editorial content
	// of the collection.
	ManagingEditor string `json:"managingEditor,omitempty" yaml:"managingEditor,omitempty"`

	// WebMaster holds an Email address for person responsible for technical issues relating to collection
	WebMaster string `json:"webMaster,omitempty" yaml:"webMaster,omitempty"`

	// PubDate holds the publication date for the content in the collection
	PubDate string `json:"pubDate,omitempty" yaml:"pubDate,omitempty"`

	// TTL is the time to live, the number of seconds to wait before trying a refresh
	TTL int `json:"ttl,omitempty" yaml:"ttl,omitempty"`

	// File holds the filepath to the Markdown document used to
	// define the collection.
	File string `json:"file,omitempty" yaml:"file,omitempty"`

	// Generator points to the YAML file to use when generating
	// a collection's HTML page.
	Generator string `json:"generator,omitempty" yaml:"generator,omitempty"`

	// Filters holds custom SQL that will be run against the Source to
	// determine which items to include and had off to the Generator.
	Filters []string `json:"filters,omitempty" yaml:"filters,omitempty"`

	// DbName holds the SQLite3 database filename
	DbName string `json:"dbName,omitempty" yaml:"dbName,omitempty"`
}

Collection describes the metadata about a collection of feeds. A collection can also be used to generate an RSS 2.0 feed of items harvested and related to the collection forming an aggregated item view of the collection of feeds.

Some of the fields from the RSS 2.0 Channel can be set from the Markdown document's front matter.

See https://cyber.harvard.edu/rss/rss.html#optionalChannelElements

func (*Collection) ApplyFilters

func (collection *Collection) ApplyFilters(db *sql.DB) error

func (*Collection) Generate

func (collection *Collection) Generate(out io.Writer, eout io.Writer, appName string, cfg *AppConfig) error

func (*Collection) Harvest

func (collection *Collection) Harvest(out io.Writer, eout io.Writer, userAgent string) error

func (*Collection) Name added in v0.0.20

func (col *Collection) Name() string

Name returns the collection basename used for the collection

func (*Collection) UpdateFrontMatter

func (collection *Collection) UpdateFrontMatter(frontMatter map[string]interface{}, cfg *AppConfig) error

type CommonMark

type CommonMark struct {
	// FrontMatter holds the object of the parsed FrontMatter if available
	// in the document.
	FrontMatter map[string]interface{} `json:"frontMatter,omitempty" yaml:"frontMatter,omitempty"`
	// Text holds the CommonMark text that comes after any front matter
	Text string `json:"text,omitempty" yaml:"text,omitempty"`
}

CommonMark holds the structure of front matter and the CommonMark text.

func (*CommonMark) GetAttributeBool

func (doc *CommonMark) GetAttributeBool(key string, defaultValue bool) bool

GetAttributeBool returns a boolean attribute from the front matter the document

func (*CommonMark) GetAttributeString

func (doc *CommonMark) GetAttributeString(key string, defaultValue string) string

GetAttributeString returns a string attribute from the front matter the document

func (doc *CommonMark) GetLinks() ([]Link, error)

GetLinks process the Text of a CommonMark struct and returns a list of Link objects if found.

func (*CommonMark) GetPersons added in v0.0.2

func (doc *CommonMark) GetPersons(key string, isRequired bool) ([]*gofeed.Person, error)

GetPersons returns a list of `*gofeed.Person{}` from the front matter in the document document

func (*CommonMark) Parse

func (doc *CommonMark) Parse(src []byte) error

Parse will read a byte slice and populate any FrontMatter found and set the remaining text as the Text element of CommonMark structure.

func (*CommonMark) ToHTML

func (doc *CommonMark) ToHTML() (string, error)

func (*CommonMark) ToUnsafeHTML added in v0.0.10

func (doc *CommonMark) ToUnsafeHTML() (string, error)

type Enclosure

type Enclosure struct {
	Url    string `json:"url,omitempty" yaml:"url,omitempty"`
	Length string `json:"length,omitempty" yaml:"length,omitempty"`
	Type   string `json:"type,omitempty" yaml:"type,omitempty"`
}

Enclosure holds the data for RSS enclusure support

type Generator

type Generator struct {
	// AppName holds the name of application running the generator
	AppName string `json:"appName,omitempty" yaml:"appName,omitempty"`

	// BaseURL used to form the feed Link
	BaseURL string `json:"base_url,omitempty" yaml:"base_url,omitempty"`

	// Version holds the version of the generator application
	// used when generating the "generator" metadata
	Version string `json:"version,omitempty" yaml:"version,omitempty"`

	// DbName holds the path to the SQLite3 database
	DBName string `json:"dbName,omitempty" yaml:"dbName,omitempty"`

	// Title if this is set the title will be included
	// when generating the markdown of saved items
	Title string `json:"title,omitempty" yaml:"title,omitempty"`

	// Description, included as metadata in head element
	Description string `json:"description,omitempty" yaml:"description,omitempty"`

	// CMarkFilters are Lua filters applied to the CommonMark document when
	// rendering HTML.
	CMarkFilters []string `json:"cm_filters,omitempty" yaml:"cm_filters,omitempty"`

	// Meta holds a list of of meta elements rendered into the head element of HTML pages
	Meta []map[string]string `json:"meta,omitempty" yaml:"meta,omitempty"`

	// Link holds the list of links elements rendered into the head element of HTML pages
	Link []map[string]string `json:"link,omitempty" yaml:"link,omitempty"`

	// Script holds a list of script elements rendered into the head element of HTML pages
	Script []map[string]string `json:"script,omitempty" yaml:"script,omitempty"`

	// Style holds an explicit Style blog that gets inserted as the last into the HTML head element
	Style string `json:"style:omitempty" yaml:"style,omitempty"`

	// Header hold the HTML markdup of the Header element. If not included
	// then it will be generated using the Title and timestamp
	Header string `json:"header,omitempty" yaml:"header,omitempty"`

	// Nav holds the HTML markup for navigation
	Nav string `json:"nav,omitempty" yaml:"nav,omitempty"`

	// TopContent holds HTML that comes before the selecton element
	// containing articles
	TopContent string `json:"top_content,omitempty" yaml:"top_content,omitempty"`

	// BottomContent holds HTML that comes before the selecton element
	// containing articles
	BottomContent string `json:"bottom_content,omitempty" yaml:"bottom_content,omitempty"`

	// Footer holds the HTML markup for the footer
	Footer string `json:"footer,omitempty" yaml:"footer,omitempty"`
	// contains filtered or unexported fields
}

Generator supports the generation of HTML pages from a YAML configuration

func NewGenerator

func NewGenerator(appName string, BaseURL string) (*Generator, error)

NewGenerator initialized a new Generator struct

func (*Generator) Generate

func (gen *Generator) Generate(eout io.Writer, appName string, cfg *AppConfig, collection *Collection) error

func (*Generator) LoadConfig

func (gen *Generator) LoadConfig(cfgName string) error

LoadConfig read in the generator configuration (not AppConfig) and map the settings into the Generator object.

func (*Generator) WriteCustomRSS added in v0.0.19

func (gen *Generator) WriteCustomRSS(out io.Writer, db *sql.DB, sqlStmt string, feedLink string, appName string, collection *Collection) error

WriteCustomRSS generates a custom RSS feed given a SQL statement

func (*Generator) WriteHTML

func (gen *Generator) WriteHTML(out io.Writer, db *sql.DB, cfgName string, collection *Collection) error

WriteHTML writes aggregated items into an HTML page from the contents of the database

func (*Generator) WriteHtmlPage

func (gen *Generator) WriteHtmlPage(htmlName string, link string, postPath, pubDate string, innerHTML string) error

WriteHtmlPage renders a post as an HTML Page using HTML connent and wrapping it based on the generator configuration.

func (*Generator) WriteItem

func (gen *Generator) WriteItem(out io.Writer, link string, title string, description string, authors []*gofeed.Person,
	sourceMarkdown string, enclosures []*Enclosure, guid string, pubDate string, dcExt string,
	channel string, status string, updated string, label string) error

Write HTML for an item

func (*Generator) WriteItemRSS

func (gen *Generator) WriteItemRSS(out io.Writer, link string, title string, description string, authors []*gofeed.Person,
	enclosures []*Enclosure, guid string, pubDate string, dcExt string,
	channel string, status string, updated string, label string, sourceMarkdown string) error

func (*Generator) WriteOPML added in v0.0.9

func (gen *Generator) WriteOPML(out io.Writer, db *sql.DB, appName string, collection *Collection) error

WriteOPML writes out the feeds being followed in collection.

func (*Generator) WriteRSS

func (gen *Generator) WriteRSS(out io.Writer, db *sql.DB, appName string, collection *Collection) error

WriteRSS writes aggregated items into an HTML page from the contents of the database

type Link struct {
	// Label holds the text label that will be used when displaying the feed
	Label string `json:"label,omitempty" yaml:"label,omitempty"`
	// The URL holds the link text to the feed
	URL string `json:"url,omitempty" yaml:"url,omitempty"`
	// The optional description holds any description text associated with the link
	Description string `json:"description,omitempty" yaml:"description,omitempty"`
}

Link represents a Markdown link with Label, URL, and optional Description.

func ParseMarkdownLinks(markdownText string) ([]Link, error)

ParseMarkdownLinks parses a Markdown text for links in the format `- [LABEL](URL "DESCRIPTION")` and returns a slice of Link structures.

type RedirectService

type RedirectService struct {
	// contains filtered or unexported fields
}

RedirectService holds our redirect targets in an ordered list and a map to our applied routes.

func MakeRedirectService

func MakeRedirectService(m map[string]string) (*RedirectService, error)

MakeRedirectService takes a m[string]string of redirects and loads it into our service's private routes attribute. It returns a new *RedirectService and error

func (*RedirectService) AddRedirectRoute

func (r *RedirectService) AddRedirectRoute(target, destination string) error

AddRedirectRoute takes a target and a destination prefix and populates the internal datastructures to handle the redirecting target prefix to the destination prefix.

func (*RedirectService) HasRedirectRoutes

func (r *RedirectService) HasRedirectRoutes() bool

HasRedirectRoutes returns true if redirects have been defined, false if not.

func (*RedirectService) HasRoute

func (r *RedirectService) HasRoute(key string) bool

HasRoute returns true if the target route is defined

func (*RedirectService) RedirectRouter

func (r *RedirectService) RedirectRouter(next http.Handler) http.Handler

RedirectRouter handles redirect requests before passing on to the handler.

func (*RedirectService) Route

func (r *RedirectService) Route(key string) (string, bool)

Route takes a target and returns a destination and bool.

type SafeFile

type SafeFile struct {
	http.File
}

SafeFile are ones that do NOT have a "." as a prefix on the path.

func (SafeFile) Readdir

func (sf SafeFile) Readdir(n int) ([]os.FileInfo, error)

Readdir wraps SafeFile method checks first if we have a dot path problem before use http.File.Readdir.

type SafeFileSystem

type SafeFileSystem struct {
	http.FileSystem
}

SafeFileSystem is used to hide dot file paths from our web services.

func MakeSafeFileSystem

func MakeSafeFileSystem(docRoot string) (SafeFileSystem, error)

MakeSafeFileSystem without a *WebService takes a doc root and returns a SafeFileSystem struct.

Example usage:

fs, err := MakeSafeFileSystem("/var/www/htdocs")

if err != nil {
    log.Fatalf("%s\n", err)
}

http.Handle("/", http.FileServer(fs)) log.Fatal(http.ListenAndService(":8000", nil))

func (SafeFileSystem) Open

func (fs SafeFileSystem) Open(p string) (http.File, error)

Open is a wrapper around the Open method of the embedded SafeFileSystem. It serves a 403 permision error when name has a file or directory who's path parts is a dot file prefix.

type Secrets

type Secrets struct {
	// NOTE: salt is needed by Argon2 and pbkdb2.
	// If the yaml/json file functions as the database then
	// this file MUST be kept safe with restricted permissions.
	// If not you just gave away your system a cracker.
	Salt []byte `json:"salt,omitempty" yaml:"salt,omitempty"`
	// Key holds the salted hash ...
	Key []byte `json:"key,omitempty" yaml:"key,omitempty"`
}

type Service

type Service struct {
	// Scheme holds the protocol to use, defaults to http if not set.
	Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
	// Host is the hostname to use, if empty "localhost" is assumed"
	Host string `json:"host,omitempty" yaml:"host,omitempty"`
	// Port is a string holding the port number to listen on
	// An empty strings defaults port to 8000
	Port string `json:"port,omitempty" yaml:"port,omitempty"`
	// CertPEM describes the location of cert.pem used for TLS support
	CertPEM string `json:"cert_pem,omitempty" yaml:"cert_pem,omitempty"`
	// KeyPEM describes the location of the key.pem used for TLS support
	KeyPEM string `json:"key_pem,omitempty" yaml:"key_pem,omitempty"`
}

Service holds the description needed to startup a service e.g. https, http.

func NewService

func NewService(scheme string, host string, port string) *Service

NewService is http, port 8000 on localhost.

func (*Service) Hostname

func (s *Service) Hostname() string

Hostname returns a host+port from a *Service

func (*Service) String

func (s *Service) String() string

String renders an URL version of *Service.

type SitemapIndex added in v0.0.16

type SitemapIndex struct {
	XMLName  xml.Name `xml:"sitemapindex"`
	Xmlns    string   `xml:"xmlns,attr"`
	Sitemaps []struct {
		Loc string `xml:"loc"`
	} `xml:"sitemap"`
}

SitemapIndex represents the root of the sitemap index XML.

type TextFragment added in v0.0.17

type TextFragment struct {
	Text    string    `json:"text,omitempty" yaml:"text,omitempty" xml:"text,omitempty"`
	Link    string    `json:"link,omitempty" yaml:"link,omitempty" yaml:"text,omitempty"`
	Host    string    `json:"host,omitempty" yaml:"host,omitempty" xml:"host,omitempty"`
	Created time.Time `json:"created,omitemtpy" yaml:"created,omitempty" xml:"created,omitempt"`
}

TextFragment holds the elements of a text fragment link along with useful metadata like time the link was created.

func ParseTextFragmentURL added in v0.0.17

func ParseTextFragmentURL(s string) (*TextFragment, error)

ParseTextFragmentURL takes a text fragment expressed as a URL and returns a TextFragment struct and error

func (*TextFragment) String added in v0.0.17

func (tf *TextFragment) String() string

String renders the text fragment as a

type URL added in v0.0.16

type URL struct {
	Loc        string `xml:"loc"`
	LastMod    string `xml:"lastmod"`
	ChangeFreq string `xml:"changefreq,omitempty"`
	Priority   string `xml:"priority,omitempty"`
}

URL represents a single URL entry in the sitemap.

type URLSet added in v0.0.16

type URLSet struct {
	XMLName xml.Name `xml:"urlset"`
	Xmlns   string   `xml:"xmlns,attr"`
	URLs    []URL    `xml:"url"`
}

URLSet represents the root of the sitemap XML.

type WebService

type WebService struct {
	// This is the document root for static file services
	// If an empty string then assume current working directory.
	DocRoot string `json:"htdocs" yaml:"htdocs"`
	// Https describes an Https service
	Https *Service `json:"https,omitempty" yaml:"https,omitempty"`
	// Http describes an Http service
	Http *Service `json:"http,omitempty" yaml:"http,omitempty"`

	// AccessFile holds a name of an access file to load and
	// populate .Access from.
	AccessFile string `json:"access_file,omitempty" yaml:"access_file,omitempty"`

	// Access adds access related features to the service.
	// E.g. BasicAUTH support.
	Access *Access `json:"access,omitempty" yaml:"access,omitempty"`

	// CORS describes the CORS policy for the web services
	CORS *CORSPolicy `json:"cors,omitempty" yaml:"cors,omitempty"`

	// ContentTypes describes a file extension mapped to a single
	// MimeType.
	ContentTypes map[string]string `json:"content_types,omitempty" yaml:"content_types,omitempty"`

	// RedirectsCSV is the filename/path to a CSV file describing
	// redirects.
	RedirectsCSV string `json:"redirects_csv,omitempty" yaml:"redirects_csv,omitempty"`

	// Redirects describes a target path to destination path.
	// Normally this is populated by a redirects.csv file.
	Redirects map[string]string `json:"redirects,omitempty" yaml:"redirects,omitempty"`

	// ReverseProxy descibes the path web paths that are sent
	// to another proxied URL.
	ReverseProxy map[string]string `json:"reverse_proxy,omitempty" yaml:"reverse_proxy,omitempty"`
}

WebService describes all the configuration and capabilities of running a wsfn based web service.

func LoadWebService

func LoadWebService(setup string) (*WebService, error)

LoadWebService loads a configuration file of *WebService

func NewWebService

func NewWebService(htdocs string, scheme string, host string, port string) *WebService

NewWebService setups to listen for http://localhost:8000 with the htdocs of the current working directory.

func (*WebService) DumpWebService

func (ws *WebService) DumpWebService(fName string) error

DumpWebService writes a access file.

func (*WebService) Run

func (w *WebService) Run() error

Run() starts a web service(s) described in the *WebService struct.

func (*WebService) SafeFileSystem

func (w *WebService) SafeFileSystem() (SafeFileSystem, error)

/ SafeFileSystem returns a new safe file system using the *WebService.DocRoot as the directory source.

Example usage:

ws := antennaApp.LoadYAML("antenna.yaml") fs, err := ws.SafeFileSystem()

if err != nil {
    log.Fatalf("%s\n", err)
}

http.Handle("/", http.FileServer(ws.SafeFileSystem())) log.Fatal(http.ListenAndService(ws.Http.Hostname(), nil))

Directories

Path Synopsis
cmd
antenna command
antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel
antennaApp is a package for creating and curating blog, link blogs and social websites Copyright (C) 2025 R. S. Doiel

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL