tseventserver

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 4, 2026 License: AGPL-3.0 Imports: 13 Imported by: 0

README

tseventserver

PkgGoDev GitHub go.mod Go version

Go Report Card CodeFactor OSS Lifecycle Libraries.io dependency status for GitHub repo

GitHub release (latest by date) GitHub last commit GitHub commit activity GitHub code size in bytes GitHub Top Language GitHub


tseventserver is a Go package for ingesting and querying economic calendar events.
It provides an HTTP API backed by Google Cloud Firestore, with a token‑authenticated
retrieval endpoint.


Features

  • IngestionPOST /events/ingest accepts an array of economic events (JSON) and
    upserts them into Firestore.
  • RetrievalGET /events/retrieve?from=…&to=… returns events within a time range,
    secured by a bearer token.
  • Google Cloud Firestore – production‑ready storage with automatic backend
    detection via GOOGLE_CLOUD_PROJECT and FIRESTORE_EMULATOR_HOST.
  • Tested – unit tests with high code coverage

Getting Started

Prerequisites
  • Go 1.26+
  • A Firestore database (or the Firestore emulator for local development)
  • Docker (for running the emulator via script)
  • (Optional) gcloud CLI for deployment to Cloud Run
Local Development with the Firestore Emulator

Option A – One‑command runner (recommended)

The run_local.sh script starts the Firestore emulator (via Docker), launches the server, and runs a quick smoke test — all in one terminal:

./run_local.sh

Press Ctrl+C to stop everything and clean up.

Option B – Manual steps

  1. Start the Firestore emulator:

    docker run -d --name firestore-emulator -p 8081:8081 \
      google/cloud-sdk:emulators \
      gcloud beta emulators firestore start --host-port=0.0.0.0:8081
    
  2. Set the required environment variables and run the server:

    export FIRESTORE_EMULATOR_HOST=localhost:8081
    export GOOGLE_CLOUD_PROJECT=demo-project
    go run ./cmd/main.go
    
  3. In another terminal, run the smoke test against the local server:

    ./smoke_test.sh http://localhost:8080
    

Note: The emulator does not persist data between restarts.

Build & Run the Binary
go build -o eventserver ./cmd/main.go
API_TOKEN=swordfish ./eventserver

The server listens on port 8080 by default (PORT env var overrides it).


Running Tests

The unit tests (nil-pointer checks, event formatting) run without any setup:

go test -v ./...

The Firestore integration tests (TestFirestoreStoreAndGetByPeriod and TestFirestoreGetByPeriodEmpty) require a running emulator and will fail with clear instructions if one is not found. Use the convenience script to run them:

./test_firestore.sh

This starts a Firestore emulator container, runs all tests (including integration), and cleans up afterwards. If you prefer to run the emulator manually:

docker run -d --name firestore-emulator -p 8081:8081 \
    google/cloud-sdk:emulators \
    gcloud beta emulators firestore start --host-port=0.0.0.0:8081

export FIRESTORE_EMULATOR_HOST=localhost:8081
go test -v ./...

docker rm -f firestore-emulator

API Reference

Authentication

Every request requires the Authorization header:

Authorization: Bearer <API_TOKEN>

The token is set via the API_TOKEN environment variable.
If omitted, the default token is swordfish (local development only).

Endpoints
POST /events/ingest

Ingest one or more economic events. Existing events (same time, country, name) are updated automatically.

Request body – JSON array of event objects:

[
  {
    "name": "US Core Inflation Rate",
    "time": "2026-05-15T12:30:00Z",
    "country": "US",
    "actual": 3.1,
    "estimate": 3.2,
    "previous": 3.3,
    "unit": "%",
    "impact": 3,
    "source": "US Bureau of Labor Statistics"
  }
]

Responses

Status Meaning
200 Events ingested successfully
400 Invalid JSON body
401 Missing or invalid token
500 Storage error
GET /events/retrieve

Retrieve events within a time window.

Query parameters

Param Required Format Example
from yes* RFC 3339 (UTC) 2026-05-01T00:00:00Z
to yes* RFC 3339 (UTC) 2026-05-31T23:59:59Z

* When from and to are omitted the endpoint returns events for the current UTC day.

Example

curl -H "Authorization: Bearer swordfish" \
  "http://localhost:8080/events/retrieve?from=2026-05-01T00:00:00Z&to=2026-05-31T23:59:59Z"

Responses

Status Meaning
200 JSON array of events (may be empty)
400 Invalid timestamp format
401 Missing or invalid token
500 Storage error

Deployment to Cloud Run

Prerequisites
  • A Firestore database named eventdb must exist in your Google Cloud project.
  • The Cloud Run service account must have the Datastore User role to read and write to Firestore.
Deploy

The included deploy.sh script handles the complete deployment. It reads configuration from environment variables (with sensible defaults for some).

Required variables

Variable Purpose
PROJECT_ID Your Google Cloud project ID
SERVICE_NAME Cloud Run service name (e.g., eventserver)
API_BEARER_KEY The token used to secure your API (set via API_TOKEN on the server)
REGION (optional) Deployment region, defaults to us-east4

Example

export PROJECT_ID=thorsphere-trading-stg
export SERVICE_NAME=eventserver
export API_BEARER_KEY=your-super-secret-token
./deploy.sh

The script sets GOOGLE_CLOUD_PROJECT and API_TOKEN automatically, ensures the eventdb Firestore database exists, and prints the service URL at the end.

Automated deployments are handled by the GitHub Actions workflow (.github/workflows/deploy.yml), which uses the same deploy.sh script.

Once deployed, verify with the smoke test:

./smoke_test.sh https://your-service.run.app

SQLite Support (Archived)

The SQLite‑backed EventRepository was used for prototyping and local development before the project moved to a Firestore‑only backend.
It has been removed from the main branch to keep the binary lean.

If you need the SQLite implementation for reference or local testing, it is available in two places:

  • GitHub GistSQLite EventRepository for tsecon
    Contains repository_sqlite.go and repository_sqlite_test.go with the full implementation and test suite.

  • Git tag v1.0.0 — The last release that includes the complete SQLite backend alongside the Firestore implementation.


License

GNU Affero General Public License v3.0 – see LICENSE for details.

Documentation

Overview

Copyright (c) 2026 thorsphere. All Rights Reserved. Use is governed with GNU Affero General Public License v3.0 that can be found in the LICENSE file.

Package tseventserver provides the core types and interfaces for economic calendar events, including an HTTP‑based ingestion and retrieval server, and pluggable storage backends (SQLite and Google Cloud Firestore).

Key types

  • Event represents a single economic release (e.g., GDP, CPI) with its actual, estimate, previous, and impact fields.
  • EventRepository is the storage interface implemented by [SQLiteEventRepository] and FirestoreEventRepository.
  • EventServer exposes authenticated HTTP endpoints: /events/ingest (POST) and /events/retrieve (GET).

Typical usage

Create a repository, then start the server:

repo, err := tseventserver.NewSQLiteEventRepository("events.db")
// ... error handling ...
defer repo.Close()
api := tseventserver.NewEventServer(repo, "your-api-token")
http.ListenAndServe(":8080", api)

Copyright (c) 2026 thorsphere. All Rights Reserved. Use is governed with GNU Affero General Public License v3.0 that can be found in the LICENSE file.

Copyright (c) 2026 thorsphere. All Rights Reserved. Use is governed with GNU Affero General Public License v3.0 that can be found in the LICENSE file.

Copyright (c) 2026 thorsphere. All Rights Reserved. Use is governed with GNU Affero General Public License v3.0 that can be found in the LICENSE file.

Copyright (c) 2026 thorsphere. All Rights Reserved. Use is governed with GNU Affero General Public License v3.0 that can be found in the LICENSE file.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Event

type Event struct {
	ID       int64       `json:"id"`       // Unique identifier for the event, e.g., a database primary key or a UUID. It is expected to be set by the database.
	Name     string      `json:"name"`     // Name of the economic event, e.g., "Non-Farm Payrolls", "GDP Growth Rate"
	Time     time.Time   `json:"time"`     // Date and time of the event in UTC, when the data is released or expected to be released
	Country  string      `json:"country"`  // ISO 3166-1 alpha-2 two-letter country code
	Actual   *float64    `json:"actual"`   // Pointer, because it can be nil if the value is not yet released
	Estimate *float64    `json:"estimate"` // Pointer, because it can be nil if the value is not yet released
	Previous *float64    `json:"previous"` // Pointer, because it can be nil if the value is not yet released
	Unit     string      `json:"unit"`     // Unit of measurement for the values, e.g., "%", "K", "M", "B"
	Impact   ImpactLevel `json:"impact"`   // Impact level of the event
	Source   string      `json:"source"`   // Source of the data, e.g., "Bloomberg", "Reuters", "Official Government Website"
}

EconomicEvent represents a single calendar event with its details. Thought: Implement a separate package for country codes and use it here for better type safety and validation.

func (Event) GenerateDocID

func (ev Event) GenerateDocID() string

GenerateDocID creates a deterministic, safe, unique document ID for NoSQL databases (like Firestore) based on the event's Time, Country, and Name.

func (Event) NearEqual

func (ev Event) NearEqual(other Event) bool

NearEqual compares two Event instances for near-equality, taking into account all fields including the pointer fields for Actual, Estimate, and Previous. It does not compare the ID field, as it is expected to be set by the database and may not be the same for two events that are otherwise identical. It returns true if all fields are equal, and false otherwise.

func (Event) String

func (ev Event) String() string

String returns a formatted string representation of the Event.

type EventRepository

type EventRepository interface {
	Store(ctx context.Context, event *Event) error                    // Store saves a new economic event to the repository. If it already exists, it should update the existing record.
	GetByPeriod(ctx context.Context, period *Period) ([]Event, error) // GetByPeriod retrieves economic events that occurred within a specified time period.
	Close() error                                                     // Close releases any resources held by the repository, such as database connections.
}

EventRepository defines the interface for managing economic events in a storage system.

type EventServer

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

EventServer is a struct that represents the event server responsible for handling event ingestion.

func NewEventServer

func NewEventServer(repo EventRepository, tok string) *EventServer

NewEventServer creates a new instance of EventServer with the provided EventRepository.

func (*EventServer) ServeHTTP

func (s *EventServer) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP makes EventServer implement the http.Handler interface, allowing it to easily route incoming requests to its internal multiplexer. This handles HTTP requests natively and is especially useful for testing.

type FirestoreEventRepository

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

FirestoreEventRepository is an implementation of the EventRepository interface that uses Google Cloud Firestore as the storage backend.

func NewFirestoreEventRepository

func NewFirestoreEventRepository(ctx context.Context, projectID string) (*FirestoreEventRepository, error)

NewFirestoreEventRepository creates a new instance of FirestoreEventRepository with the provided Google Cloud project ID.

func (*FirestoreEventRepository) Close

func (r *FirestoreEventRepository) Close() error

Close closes the connection to the Firestore database and releases any associated resources.

func (*FirestoreEventRepository) GetByPeriod

func (r *FirestoreEventRepository) GetByPeriod(ctx context.Context, period *Period) ([]Event, error)

GetByPeriod retrieves economic events that occurred within a specified time period.

func (*FirestoreEventRepository) Store

func (r *FirestoreEventRepository) Store(ctx context.Context, event *Event) error

Store saves a new economic event to the FirestoreEventRepository. It generates a deterministic document ID to seamlessly perform an upsert.

type ImpactLevel

type ImpactLevel int

ImpactLevel represents the expected market impact of an economic event.

const (
	ImpactLow    ImpactLevel = iota // iota starts at 0, so ImpactLow = 0
	ImpactMedium                    // ImpactMedium = 1
	ImpactHigh                      // ImpactHigh = 2
)

Define constants for the different impact levels.

func (ImpactLevel) String

func (i ImpactLevel) String() string

String returns a string representation of the ImpactLevel.

type Period

type Period struct {
	From time.Time // Start date and time of the period
	To   time.Time // End date and time of the period
}

Period represents a time period with a start and end date.

func NewPeriodForDate

func NewPeriodForDate(date time.Time) *Period

NewPeriodForDate creates a Period that spans the entire given date (00:00:00 to 23:59:59) in UTC.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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