diff options
Diffstat (limited to 'tools/blog_cli')
-rw-r--r-- | tools/blog_cli/README.md | 41 | ||||
-rw-r--r-- | tools/blog_cli/default.nix | 9 | ||||
-rw-r--r-- | tools/blog_cli/main.go | 209 |
3 files changed, 0 insertions, 259 deletions
diff --git a/tools/blog_cli/README.md b/tools/blog_cli/README.md deleted file mode 100644 index 7afa0fe9207a..000000000000 --- a/tools/blog_cli/README.md +++ /dev/null @@ -1,41 +0,0 @@ -tazblog CLI -=========== - -My blog stores its content in DNS, spread out over three types of `TXT` entries: - -* `TXT _posts.blog.tazj.in.`: A sorted list of posts, serialised as a JSON list of - strings (e.g. `["1486830338", "1476807384"]`) - -* `TXT _chunks.$postID.blog.tazj.in`: JSON chunks containing the blog post text - -* `TXT _meta.$postID.blog.tazj.in`: JSON blob with blog post metadata - -All JSON blobs are base64-encoded. - -This CLI tool helps to update those records. - -Each blog post data is a series of JSON-encoded structures which follow one of -these formats: - -``` -struct metadata { - chunks: int - title: string - date: date -} -``` - -Where `chunks` describes the number of chunks following this format: - -``` -struct chunk { - c: int - t: string -} -``` - -Writing a blog post to DNS means taking its text and metadata, chunking it up -and writing the chunks. - -Reading a blog post means retrieving all data, reading the metadata and then -assembling the chunks in order. diff --git a/tools/blog_cli/default.nix b/tools/blog_cli/default.nix deleted file mode 100644 index c22e4c949bc1..000000000000 --- a/tools/blog_cli/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ pkgs, ... }: - -pkgs.buildGo.program { - name = "blog_cli"; - srcs = [ ./main.go ]; - deps = with pkgs.third_party; [ - gopkgs."google.golang.org".api.dns.v1.gopkg - ]; -} // { meta.enableCI = true; } diff --git a/tools/blog_cli/main.go b/tools/blog_cli/main.go deleted file mode 100644 index db64f8378e40..000000000000 --- a/tools/blog_cli/main.go +++ /dev/null @@ -1,209 +0,0 @@ -// The tazblog CLI implements updating my blog records in DNS, see the -// README in this folder for details. -// -// The post input format is a file with the title on one line, -// followed by the date on a line, followed by an empty line, followed -// by the post text. -package main - -import ( - "context" - "encoding/base64" - "encoding/json" - "flag" - "fmt" - "io/ioutil" - "log" - "time" - - "google.golang.org/api/dns/v1" -) - -var ( - project = flag.String("project", "tazjins-infrastructure", "Target GCP project") - zone = flag.String("zone", "blog-tazj-in", "Target Cloud DNS zone") - title = flag.String("title", "", "Title of the blog post") - date = flag.String("date", "", "Date the post was written on") - infile = flag.String("text", "", "Text file containing the blog post") - id = flag.String("id", "", "Post ID - will be generated if unset") -) - -// Number of runes to include in a single chunk. If any chunks exceed -// the limit of what can be encoded, the chunk size is reduced and we -// try again. -var chunkSize = 200 - -type day time.Time - -func (d day) MarshalJSON() ([]byte, error) { - j := (time.Time(d)).Format(`"2006-01-02"`) - return []byte(j), nil -} - -type metadata struct { - Chunks int `json:"c"` - Title string `json:"t"` - Date day `json:"d"` -} - -type chunk struct { - Chunk int - Text string -} - -type post struct { - ID string - Meta metadata - Chunks []string -} - -func (p *post) writeToDNS() error { - var additions []*dns.ResourceRecordSet - additions = append(additions, &dns.ResourceRecordSet{ - Name: fmt.Sprintf("_meta.%s.blog.tazj.in.", p.ID), - Type: "TXT", - Ttl: 1200, - Rrdatas: []string{ - encodeJSON(p.Meta), - }, - }) - - for i, c := range p.Chunks { - additions = append(additions, &dns.ResourceRecordSet{ - Name: fmt.Sprintf("_%v.%s.blog.tazj.in.", i, p.ID), - Type: "TXT", - Ttl: 1200, - Rrdatas: []string{c}, - }) - } - - ctx := context.Background() - dnsSvc, err := dns.NewService(ctx) - if err != nil { - return err - } - - change := dns.Change{ - Additions: additions, - } - - _, err = dnsSvc.Changes.Create(*project, *zone, &change).Do() - if err != nil { - return err - } - - return nil -} - -// Encode given value as JSON and base64-encode it. -func encodeJSON(v interface{}) string { - outer, err := json.Marshal(v) - if err != nil { - log.Fatalln("Failed to encode JSON", err) - } - - return base64.RawStdEncoding.EncodeToString(outer) -} - -// Encode a chunk and check whether it is too large -func encodeChunk(c chunk) (string, bool) { - tooLarge := false - s := base64.RawStdEncoding.EncodeToString([]byte(c.Text)) - - if len(s) >= 255 { - tooLarge = true - } - - return s, tooLarge -} - -func createPost(id, title, text string, date day) post { - runes := []rune(text) - n := 0 - tooLarge := false - - var chunks []string - - for chunkSize < len(runes) { - c, l := encodeChunk(chunk{ - Chunk: n, - Text: string(runes[0:chunkSize:chunkSize]), - }) - - tooLarge = tooLarge || l - chunks = append(chunks, c) - runes = runes[chunkSize:] - n++ - } - - if len(runes) > 0 { - c, l := encodeChunk(chunk{ - Chunk: n, - Text: string(runes), - }) - - tooLarge = tooLarge || l - chunks = append(chunks, c) - n++ - } - - if tooLarge { - log.Println("Too large at chunk size", chunkSize) - chunkSize -= 5 - return createPost(id, title, text, date) - } - - return post{ - ID: id, - Meta: metadata{ - Chunks: n, - Title: title, - Date: date, - }, - Chunks: chunks, - } -} - -func main() { - flag.Parse() - - if *title == "" { - log.Fatalln("Post title must be set (-title)") - } - - if *infile == "" { - log.Fatalln("Post text file must be set (-text)") - } - - if *id == "" { - log.Fatalln("Post ID must be set (-id)") - } - - var postDate day - if *date != "" { - t, err := time.Parse("2006-01-02", *date) - if err != nil { - log.Fatalln("Invalid post date", err) - } - - postDate = day(t) - } else { - postDate = day(time.Now()) - } - - t, err := ioutil.ReadFile(*infile) - if err != nil { - log.Fatalln("Failed to read post:", err) - } - - post := createPost(*id, *title, string(t), postDate) - - log.Println("Writing post to DNS ...") - err = post.writeToDNS() - - if err != nil { - log.Fatalln("Failed to write post:", err) - } - - log.Println("Successfully wrote entries") -} |