Skip to content

Writing a Data Source

Matt Holt edited this page Dec 23, 2020 · 6 revisions

Data sources are how Timeliner creates and configures Clients, which are used to list the items on the data source.

Create a package in the datasources folder named after the data source you are implementing. Typically the package name will be the data source ID but without underscores. For example, google_location would be package googlelocation. (It's like echolocation but through Google... get it?) The folder name should be the same as the package name.

It is conventional to:

  • Export the constants DataSourceName and DataSourceID
  • Name the type that implements timeliner.Client also Client
  • Avoid adding large dependencies, e.g. API client libraries are often unnecessary/cumbersome

Here are links to relevant godoc documentation you will need to know:

And here is a template file to get you started:

// Package ____ implements a Timeliner data source for ____. (TODO)
package ____

import (
	"context"
	"io"
	"log"
	"time"

	"github.com/mholt/timeliner"
)

// Data source name and ID.
const (
	DataSourceName = "____" // TODO: brand name
	DataSourceID   = "____" // TODO: snake_cased unique name
)

// TODO: configure your data source here; see godoc for available fields
var dataSource = timeliner.DataSource{
	ID:   DataSourceID,
	Name: DataSourceName,
	NewClient: func(acc timeliner.Account) (timeliner.Client, error) {
		// TODO: If you If you need an HTTP client for accessing your service,
		// call acc.NewHTTPClient(). It will be preloaded with OAuth2 (if
		// configured) and a built-in rate limiter (if configured).
		return new(Client), nil
	},
}

func init() {
	err := timeliner.RegisterDataSource(dataSource)
	if err != nil {
		log.Fatal(err)
	}
}

// Client implements the timeliner.Client interface.
type Client struct{}

// ListItems lists items from the data source.
func (c *Client) ListItems(ctx context.Context, itemChan chan<- *timeliner.ItemGraph, opt timeliner.ListingOptions) error {
	defer close(itemChan)

	// TODO: read the godoc for the timeliner.Client interface and
	// follow it carefully when implementing ListItems.

	return nil
}

// TODO: A timeliner.Item can be any type that
// is considered a data point, or "item", to
// be stored in the timeline.
type myItem struct {
}

func (item myItem) ID() string {
	return "" // TODO: REQUIRED
}

func (item myItem) Timestamp() time.Time {
	return time.Time{} // TODO: REQUIRED
}

func (item myItem) Class() timeliner.ItemClass {
	return timeliner.ClassUnknown // TODO: REQUIRED
}

func (item myItem) Owner() (id *string, name *string) {
	return nil, nil
}

func (item myItem) DataText() (*string, error) {
	return nil, nil
}

func (item myItem) DataFileName() *string {
	return nil
}

func (item myItem) DataFileReader() (io.ReadCloser, error) {
	return nil, nil
}

func (item myItem) DataFileHash() []byte {
	return nil
}

func (item myItem) DataFileMIMEType() *string {
	return nil
}

func (item myItem) Metadata() (*timeliner.Metadata, error) {
	return nil, nil
}

func (item myItem) Location() (*timeliner.Location, error) {
	return nil, nil
}

Once your new package is ready, you will need to import it in the main.go file to "plug it in".

Clone this wiki locally