-
-
Notifications
You must be signed in to change notification settings - Fork 116
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
andDataSourceID
- Name the type that implements
timeliner.Client
alsoClient
- 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:
package timeliner
type DataSource
-
type Client
(interacts with the data source; simply has to list items) -
type Item
(the "meat and potatoes") -
type ItemGraph
(relationships between items) -
type Collection
(any grouping of items)
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".