gdnotify

package module
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: Jan 8, 2026 License: MIT Imports: 54 Imported by: 0

README

gdnotify

Documentation Latest GitHub release Github Actions test License

gdnotify is a Google Drive change notifier for AWS.

Changes that occur in Google Drive are notified through Amazon EventBridge.

Install

Homebrew (macOS and Linux)
$ brew install mashiike/tap/awstee
Binary packages

Releases

Usage

$ gdnotify -h
Usage: gdnotify <command> [flags]

gdnotify is a tool for managing notification channels for Google Drive.

Flags:
  -h, --help                                         Show context-sensitive help.
      --log-level="info"                             log level ($GDNOTIFY_LOG_LEVEL)
      --log-format="text"                            log format ($GDNOTIFY_LOG_FORMAT)
      --[no-]log-color                               enable color output ($GDNOTIFY_LOG_COLOR)
      --version                                      show version
      --storage-type="dynamodb"                      storage type ($GDNOTIFY_STORAGE_TYPE)
      --storage-table-name="gdnotify"                dynamodb table name ($GDNOTIFY_DDB_TABLE_NAME)
      --[no-]storage-auto-create                     auto create dynamodb table ($GDNOTIFY_DDB_AUTO_CREATE)
      --storage-dynamo-db-endpoint=STRING            dynamodb endpoint ($GDNOTIFY_DDB_ENDPOINT)
      --storage-data-file="gdnotify.dat"             file storage data file ($GDNOTIFY_FILE_STORAGE_DATA_FILE)
      --storage-lock-file="gdnotify.lock"            file storage lock file ($GDNOTIFY_FILE_STORAGE_LOCK_FILE)
      --notification-type="eventbridge"              notification type ($GDNOTIFY_NOTIFICATION_TYPE)
      --notification-event-bus="default"             event bus name (eventbridge type only) ($GDNOTIFY_EVENTBRIDGE_EVENT_BUS)
      --notification-event-file="gdnotify.json"      event file path (file type only) ($GDNOTIFY_EVENT_FILE)
      --webhook=""                                   webhook address ($GDNOTIFY_WEBHOOK)
      --expiration=168h                              channel expiration ($GDNOTIFY_EXPIRATION)
      --within-modified-time=WITHIN-MODIFIED-TIME    within modified time, If the edit time is not within this time, notifications will not be sent ($GDNOTIFY_WITHIN_MODIFIED_TIME).

Commands:
  list [flags]
    list notification channels

  serve [flags]
    serve webhook server

  cleanup [flags]
    remove all notification channels

  sync [flags]
    force sync notification channels; re-register expired notification channels,register new unregistered channels and get all new notification

Run "gdnotify <command> --help" for more information on a command.

Refer to the following document to prepare the permissions for Google Cloud. Please enable the Google Drive API v3 in the corresponding Google Cloud in advance. https://cloud.google.com/docs/authentication/application-default-credentials

Start the server with gdnotify as follows.

$ go run cmd/gdnotify/main.go --storage-auto-create                  
time=2025-03-13T19:29:17.799+09:00 level=INFO msg="check describe dynamodb table" table_name=gdnotify
time=2025-03-13T19:29:18.379+09:00 level=INFO msg="starting up with local httpd :25254"

By default, the server will start at :25254. By specifying the --storage-auto-create option, the DynamoDB table will be created automatically.

Here, use the Tonnel function of VSCode, etc., to make it accessible from the outside. If it becomes accessible at an address like https://xxxxxxxx-25254.asse.devtunnels.ms/, access it as follows.

$ curl -X POST https://xxxxxxxx-25254.asse.devtunnels.ms/sync

Then, notifications to EventBridge will start. The following diagram illustrates what happens.

sequenceDiagram
  autonumber
  gdnotify [/sync]->>+Google API: GET /drive/v3/changes/startPageToken
  Google API-->>-gdnotify [/sync]: PageToken
  gdnotify [/sync]->>+Google API: POST /drive/v3/changes/watch
  Google API [push]--)gdnotify [/]:  sync request
  Google API-->>-gdnotify [/sync]: response
  gdnotify [/sync]->>+DynamoDB: put item
  DynamoDB-->>-gdnotify [/sync]: response
  loop
    Google API [push]->>+gdnotify [/]: change request
    gdnotify [/]->>+Google API: GET /drive/v3/changes
    Google API-->>- gdnotify [/]: changes info
     gdnotify [/]->>+EventBridge: Put Events
    EventBridge-->>- gdnotify [/]: response
     gdnotify [/]->>+DynamoDB: update item
    DynamoDB-->>- gdnotify [/]: response
    gdnotify [/]->>+Google API [push]: Status Ok
  end

Usage with AWS Lambda

gdnotify can run as a Lambda runtime. Therefore, by deploying the binary as a Lambda function, you can easily receive Google Drive change notifications via EventBridge.

Let's solidify the Lambda package with the following configuration (runtime provided.al2023)

lambda.zip
└── bootstrap    # build binary

For more details, refer to Lambda Example.

The IAM permissions required are as follows, in addition to AWSLambdaBasicExecutionRole:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Webhook",
            "Effect": "Allow",
            "Action": [
                "events:PutEvents",
                "dynamodb:DescribeTable",
                "dynamodb:GetItem",
                "dynamodb:UpdateItem",
                "dynamodb:CreateTable",
                "dynamodb:PutItem",
                "dynamodb:DeleteItem",
                "dynamodb:Scan"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

A related document is https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html

When the Lambda function is invoked directly, it behaves as if a request was made to the /sync endpoint. It is recommended to periodically invoke the Lambda function using EventBridge Scheduler, etc. The /sync endpoint performs notification channel rotation and forced change notification synchronization.

To receive change notifications from the Google Drive API, you need to set up a Lambda Function URL, API Gateway, ALB, etc. The simplest is the Lambda Function URL, so here is a reference link.

lambda function URLs document is https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html

S3 Copy Feature (Optional)

gdnotify can optionally copy files from Google Drive to S3 when changes are detected. This eliminates the need for downstream Lambda functions to implement Google Drive API authentication and file download logic.

Enabling S3 Copy

Use the --s3-copy-config flag to specify a YAML configuration file:

gdnotify serve --s3-copy-config=./s3copy.yaml

Or set the environment variable:

export GDNOTIFY_S3_COPY_CONFIG=./s3copy.yaml
Configuration File Format

The configuration file uses YAML with CEL (Common Expression Language) expressions for flexible rule-based copying.

# s3copy.yaml

# Default bucket and object key (used when rules don't specify them)
bucket_name: env("GDNOTIFY_S3_BUCKET")
object_key: '"files/" + entity.id + "/" + entity.name'

rules:
  # Google Slides -> Export as PDF
  - when: change.file.mimeType == "application/vnd.google-apps.presentation"
    export: pdf
    object_key: '"slides/" + entity.id + "/" + entity.name + ".pdf"'

  # Google Sheets -> Export as CSV
  - when: change.file.mimeType == "application/vnd.google-apps.spreadsheet"
    export: csv
    object_key: '"sheets/" + entity.id + "/" + entity.name + ".csv"'

  # Images -> Download as-is
  - when: change.file.mimeType.startsWith("image/")
    object_key: '"images/" + entity.id + "/" + entity.name'

  # Skip large files (example)
  - when: 'int(change.file.size) > 100 * 1024 * 1024'
    skip: true
Rule Evaluation
  1. Rules are evaluated top-to-bottom
  2. The first matching rule (where when evaluates to true) is applied
  3. If skip: true, the file is not copied to S3
  4. If no rule matches, the file is not copied
  5. Removed files (change.removed = true) are always skipped automatically
CEL Variables

The following variables are available in CEL expressions:

Variable Type Description
subject string Event subject line
entity.id string File or Drive ID
entity.kind string Entity kind (drive#file, drive#drive)
entity.name string File or Drive name
actor.displayName string User's display name
actor.emailAddress string User's email address
change.changeType string Change type (file, drive)
change.removed bool Whether the file was removed
change.time string Change timestamp
change.fileId string File ID
change.file.mimeType string File MIME type
change.file.size string File size in bytes
change.file.name string File name
CEL Functions
Function Description
env("VAR_NAME") Get environment variable value
startsWith(prefix) Check if string starts with prefix
endsWith(suffix) Check if string ends with suffix
contains(substr) Check if string contains substring
matches(regex) Check if string matches regex
Export Formats

For Google Workspace files that cannot be downloaded directly, use the export field:

The default export format is pdf when export is omitted.

File Type Export Options
Google Docs pdf, docx, txt, html, odt, rtf
Google Sheets pdf, xlsx, csv, ods
Google Slides pdf, pptx, odp
Google Drawings pdf, png, jpeg, svg
IAM Permissions for S3 Copy

Add the following permissions to the Lambda execution role:

{
    "Action": [
        "s3:PutObject",
        "s3:GetObject"
    ],
    "Effect": "Allow",
    "Resource": "arn:aws:s3:::your-bucket-name/*"
}
Validating Configuration

You can validate your S3 copy configuration file:

gdnotify validate --s3-copy-config=./s3copy.yaml

EventBridge Event Payload

Finally, the notified event is notified with the following detail.

{
  "subject": "File gdnotify (XXXXXXXXXX) changed by hoge [[email protected]] at 2022-06-15T00:03:45.843Z",
  "entity": {
    "id": "XXXXXXXXXX",
    "kind": "drive#file",
    "name": "gdnotify",
    "createdTime": ""
  },
  "actor": {
    "displayName": "hoge",
    "emailAddress": "[email protected]",
    "kind": "drive#user"
  },
  "change": {
    "changeType": "file",
    "file": {
      "id": "XXXXXXXXXX",
      "kind": "drive#file",
      "lastModifyingUser": {
        "displayName": "hoge",
        "emailAddress": "[email protected]",
        "kind": "drive#user"
      },
      "mimeType": "application/vnd.google-apps.spreadsheet",
      "modifiedTime": "2022-06-15T00:03:45.843Z",
      "name": "gdnotify",
      "size": "1500",
      "version": "20"
    },
    "fileId": "XXXXXXXXXX",
    "kind": "drive#change",
    "time": "2022-06-15T00:03:55.849Z"
  },
  "s3Copy": {
    "s3Uri": "s3://my-bucket/sheets/XXXXXXXXXX/gdnotify.csv",
    "contentType": "text/csv",
    "size": 1234,
    "copiedAt": "2022-06-15T00:03:56.123Z"
  }
}

Note: The s3Copy field is only present when S3 copy is enabled and the file matches a copy rule. If no rule matches or skip: true, this field will be absent.

For example, if you set the following event pattern, all events will trigger the rule.

{
    "source" : [{
    "prefix" : "oss.gdnotify"
    }]
}

If you specify the following event rule, you can narrow it down to only file-related notifications.

{
    "source": [{
        "prefix":"oss.gdnotify"
    }],
    "detail":{
        "subject":[{
            "prefix": "File"
        }]
    }
}

Set any EventBridge rules and connect to the subsequent processing.

LICENSE

MIT License

Copyright (c) 2022 IKEDA Masashi

Documentation

Overview

Package gdnotify provides a Google Drive change notification system for AWS.

gdnotify monitors changes in Google Drive using the Push Notifications API and forwards them to Amazon EventBridge. It manages notification channels, handles webhook callbacks from Google Drive, and maintains channel state using DynamoDB or local file storage.

Architecture

The package consists of three main components:

  • App: Core application that coordinates channel management and change processing
  • Storage: Persistent storage for notification channel state (DynamoDB or file-based)
  • Notification: Event delivery to downstream systems (EventBridge or file-based)

Usage

For CLI usage, create a CLI instance and call Run:

var cli gdnotify.CLI
ctx := context.Background()
exitCode := cli.Run(ctx)

For programmatic usage, create an App instance:

storage, _ := gdnotify.NewStorage(ctx, storageOption)
notification, _ := gdnotify.NewNotification(ctx, notificationOption)
app, _ := gdnotify.New(appOption, storage, notification)
defer app.Close()

Google Drive Integration

gdnotify uses the Google Drive API v3 Push Notifications feature. When changes occur in Google Drive, Google sends webhook callbacks to the configured endpoint. The app then fetches the actual changes using the Changes API and forwards them to EventBridge.

AWS Integration

The package integrates with AWS services:

  • DynamoDB for channel state persistence
  • EventBridge for change event delivery
  • Lambda for serverless deployment (via github.com/fujiwara/ridge)

Deployment Modes

gdnotify supports multiple deployment modes:

  • Local HTTP server for development
  • AWS Lambda with Function URL or API Gateway
  • Hybrid mode supporting both local and Lambda environments

Index

Constants

View Source
const (
	DefaultDriveID   = "__default__"
	DefaultDriveName = "My Drive and Individual Files"
)

Constants for representing the user's personal "My Drive" and individual files. These are used when no specific shared drive is targeted.

View Source
const (
	DetailTypeFileRemoved  = "File Removed"
	DetailTypeFileTrashed  = "File Move to trash"
	DetailTypeFileChanged  = "File Changed"
	DetailTypeDriveRemoved = "Shared Drive Removed"
	DetailTypeDriveChanged = "Drive Status Changed"
)

DetailType constants for EventBridge events.

Variables

View Source
var ExportMIMETypes = map[string]string{
	"pdf":  "application/pdf",
	"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
	"docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
	"pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
	"csv":  "text/csv",
	"txt":  "text/plain",
	"html": "text/html",
	"rtf":  "application/rtf",
	"odt":  "application/vnd.oasis.opendocument.text",
	"ods":  "application/vnd.oasis.opendocument.spreadsheet",
	"odp":  "application/vnd.oasis.opendocument.presentation",
	"png":  "image/png",
	"jpeg": "image/jpeg",
	"svg":  "image/svg+xml",
}

ExportMIMETypes maps export format names to MIME types. Used for exporting Google Workspace files to standard formats.

View Source
var Version = "v0.6.1"

Functions

func ConvertChange added in v0.6.0

func ConvertChange(c *drive.Change) *gdnotifyevent.Change

func ConvertDrive added in v0.6.0

func ConvertDrive(d *drive.Drive) *gdnotifyevent.Drive

func ConvertFile added in v0.6.0

func ConvertFile(f *drive.File) *gdnotifyevent.File

func ConvertToDetail added in v0.6.0

func ConvertToDetail(c *drive.Change) *gdnotifyevent.Detail

ConvertToDetail converts a drive.Change to a gdnotifyevent.Detail with Subject, Entity, and Actor populated.

func ConvertUser added in v0.6.0

func ConvertUser(u *drive.User) *gdnotifyevent.User

func DetailType added in v0.6.0

func DetailType(c *gdnotifyevent.Change) string

DetailType returns the EventBridge detail-type for a change.

func GetAttributeValueAs

func GetAttributeValueAs[T types.AttributeValue](key string, values map[string]types.AttributeValue) (T, bool)

func IsGoogleWorkspaceFile added in v0.6.0

func IsGoogleWorkspaceFile(mimeType string) bool

IsGoogleWorkspaceFile returns true if the MIME type is a Google Workspace file.

func IterMap added in v0.5.0

func IterMap[E, F any](seq iter.Seq[E], fn func(E) F) iter.Seq[F]

func KeyValues added in v0.5.0

func KeyValues[E, V any, K comparable](s []E, fn func(E) (K, V)) map[K]V

func Map added in v0.5.0

func Map[E, F any](s []E, fn func(E) F) []F

func SetAWSConfig added in v0.5.0

func SetAWSConfig(cfg aws.Config)

SetAWSConfig sets a custom AWS configuration for the application. This is useful for testing or when running outside of AWS with custom credentials. If not called, the default AWS configuration is loaded automatically.

Types

type App

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

App is the core application that manages Google Drive notification channels. It coordinates between Storage for persistence and Notification for event delivery.

App handles:

  • Creating and managing Google Drive push notification channels
  • Processing webhook callbacks from Google Drive
  • Fetching and forwarding change events
  • Automatic channel rotation before expiration

func New

func New(cfg AppOption, storage Storage, notification Notification, gcpOpts ...option.ClientOption) (*App, error)

New creates a new App instance with the provided configuration.

The storage parameter is used to persist channel state, and notification is used to deliver change events. The gcpOpts are passed to the Google Drive API client for authentication.

Example:

storage, _ := NewStorage(ctx, storageOpt)
notification, _ := NewNotification(ctx, notificationOpt)
app, err := New(appOpt, storage, notification)

func (*App) ChangesList

func (app *App) ChangesList(ctx context.Context, channelID string) ([]*drive.Change, *ChannelItem, error)

func (*App) Cleanup added in v0.5.0

func (app *App) Cleanup(ctx context.Context, _ CleanupOption) error

func (*App) Close

func (app *App) Close() error

func (*App) CreateChannel

func (app *App) CreateChannel(ctx context.Context, driveID string) error

func (*App) DeleteChannel

func (app *App) DeleteChannel(ctx context.Context, item *ChannelItem) error

func (*App) DriveIDs added in v0.4.0

func (app *App) DriveIDs(ctx context.Context) ([]string, error)

func (*App) Drives added in v0.5.0

func (app *App) Drives(ctx context.Context) ([]*drive.Drive, error)

func (*App) List added in v0.5.0

func (app *App) List(ctx context.Context, o ListOption) error

func (*App) RotateChannel

func (app *App) RotateChannel(ctx context.Context, item *ChannelItem) error

func (*App) SendNotification added in v0.3.0

func (app *App) SendNotification(ctx context.Context, item *ChannelItem, changes []*drive.Change) error

func (*App) Serve added in v0.5.0

func (app *App) Serve(ctx context.Context, o ServeOption) error

func (*App) ServeHTTP

func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*App) SetS3Copier added in v0.6.0

func (app *App) SetS3Copier(copier *S3Copier)

SetS3Copier sets the S3Copier for copying files to S3. If set, files matching the S3CopyConfig rules will be copied to S3 before sending notifications.

func (*App) Sync added in v0.5.0

func (app *App) Sync(ctx context.Context, _ SyncOption) error

type AppOption added in v0.5.0

type AppOption struct {
	Webhook            string         `help:"webhook address" default:"" env:"GDNOTIFY_WEBHOOK"`
	Expiration         time.Duration  `help:"channel expiration" default:"168h" env:"GDNOTIFY_EXPIRATION"`
	WithinModifiedTime *time.Duration `` /* 138-byte string literal not displayed */
}

AppOption contains configuration options for creating an App.

Fields:

  • Webhook: The public URL where Google Drive will send push notifications
  • Expiration: How long a notification channel remains valid (default: 168h)
  • WithinModifiedTime: Optional filter to ignore changes older than this duration

type CELEnv added in v0.6.0

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

CELEnv provides a CEL environment configured for evaluating expressions against gdnotifyevent.Detail.

func NewCELEnv added in v0.6.0

func NewCELEnv() (*CELEnv, error)

NewCELEnv creates a new CEL environment with gdnotifyevent types registered. Field names in CEL expressions use lowerCamelCase (matching JSON tags), e.g., change.fileId, change.file.mimeType, entity.createdTime.

func (*CELEnv) Compile added in v0.6.0

func (e *CELEnv) Compile(expr string) (*CompiledExpression, error)

Compile compiles a CEL expression string.

func (*CELEnv) CompileString added in v0.6.0

func (e *CELEnv) CompileString(expr string) (*StringExpression, error)

CompileString compiles a CEL expression that returns a string.

type CLI added in v0.5.0

type CLI struct {
	LogLevel     string             `help:"log level" default:"info" env:"GDNOTIFY_LOG_LEVEL"`
	LogFormat    string             `help:"log format" default:"text" enum:"text,json" env:"GDNOTIFY_LOG_FORMAT"`
	LogColor     bool               `help:"enable color output" default:"true" env:"GDNOTIFY_LOG_COLOR" negatable:""`
	Version      kong.VersionFlag   `help:"show version"`
	Storage      StorageOption      `embed:"" prefix:"storage-"`
	Notification NotificationOption `embed:"" prefix:"notification-"`
	S3CopyConfig string             `name:"s3-copy-config" help:"path to S3 copy configuration file" env:"GDNOTIFY_S3_COPY_CONFIG"`
	AppOption    `embed:""`

	List     ListOption     `cmd:"" help:"list notification channels"`
	Serve    ServeOption    `cmd:"" help:"serve webhook server" default:"true"`
	Cleanup  CleanupOption  `cmd:"" help:"remove all notification channels"`
	Sync     SyncOption     `` /* 153-byte string literal not displayed */
	Validate ValidateOption `cmd:"" help:"validate configuration files"`
}

CLI is the command-line interface for gdnotify.

Use the Run method to execute the CLI:

var cli gdnotify.CLI
ctx := context.Background()
exitCode := cli.Run(ctx)

Available commands:

  • serve: Start the webhook server (default)
  • list: List registered notification channels
  • sync: Force synchronization of all channels
  • cleanup: Remove all notification channels
  • validate: Validate configuration files

func (*CLI) Run added in v0.5.0

func (c *CLI) Run(ctx context.Context) int

Run parses command-line arguments and executes the appropriate command. Returns 0 on success, 1 on error.

type ChannelAlreadyExists

type ChannelAlreadyExists struct {
	ChannelID string
}

ChannelAlreadyExists is returned when attempting to create a duplicate channel.

func (*ChannelAlreadyExists) Error

func (err *ChannelAlreadyExists) Error() string

type ChannelItem

type ChannelItem struct {
	ChannelID          string    // Unique identifier for this channel
	Expiration         time.Time // When this channel expires
	PageToken          string    // Token for fetching incremental changes
	ResourceID         string    // Google's resource identifier for the channel
	DriveID            string    // Target drive ID (or DefaultDriveID for personal drive)
	PageTokenFetchedAt time.Time // When the page token was last fetched
	CreatedAt          time.Time // Channel creation timestamp
	UpdatedAt          time.Time // Last update timestamp
}

ChannelItem represents a Google Drive push notification channel.

Each channel monitors changes in a specific drive (or "My Drive" for DefaultDriveID) and tracks the page token for incremental change fetching.

func NewChannelItemWithDynamoDBAttributeValues

func NewChannelItemWithDynamoDBAttributeValues(values map[string]types.AttributeValue) *ChannelItem

func (*ChannelItem) IsAboutToExpired

func (item *ChannelItem) IsAboutToExpired(ctx context.Context, remaining time.Duration) bool

func (*ChannelItem) ToDynamoDBAttributeValues

func (item *ChannelItem) ToDynamoDBAttributeValues() map[string]types.AttributeValue

type ChannelNotFoundError added in v0.5.0

type ChannelNotFoundError struct {
	ChannelID string
}

ChannelNotFoundError is returned when a channel lookup fails.

func (*ChannelNotFoundError) Error added in v0.5.0

func (err *ChannelNotFoundError) Error() string

type CleanupOption added in v0.5.0

type CleanupOption struct {
}

CleanupOption contains options for the cleanup command.

type CompiledExpression added in v0.6.0

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

CompiledExpression represents a compiled CEL expression.

func (*CompiledExpression) Eval added in v0.6.0

func (c *CompiledExpression) Eval(detail *gdnotifyevent.Detail) (bool, error)

Eval evaluates the compiled expression against the given detail.

type CopyResult added in v0.6.0

type CopyResult struct {
	S3URI       string
	ContentType string
	Size        int64
	CopiedAt    time.Time
}

CopyResult contains the result of a copy operation.

type DownloadResult added in v0.6.0

type DownloadResult struct {
	Body        io.ReadCloser
	ContentType string
	Size        int64
}

DownloadResult contains the result of a download or export operation.

type DriveDownloader added in v0.6.0

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

DriveDownloader handles file downloads and exports from Google Drive.

func NewDriveDownloader added in v0.6.0

func NewDriveDownloader(svc *drive.Service) *DriveDownloader

NewDriveDownloader creates a new DriveDownloader with the given service.

func (*DriveDownloader) Download added in v0.6.0

func (d *DriveDownloader) Download(ctx context.Context, fileID string) (*DownloadResult, error)

Download downloads a regular file from Google Drive. Returns the file content, content type, and any error.

func (*DriveDownloader) DownloadOrExport added in v0.6.0

func (d *DriveDownloader) DownloadOrExport(ctx context.Context, fileID, fileMimeType, exportFormat string) (*DownloadResult, error)

DownloadOrExport downloads a file or exports it based on its MIME type. For Google Workspace files, exports to the specified format (default: pdf). For regular files, downloads the original.

func (*DriveDownloader) Export added in v0.6.0

func (d *DriveDownloader) Export(ctx context.Context, fileID, format string) (*DownloadResult, error)

Export exports a Google Workspace file to the specified format. format should be one of: pdf, xlsx, docx, pptx, csv, txt, html, etc.

type DynamoDBStorage

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

DynamoDBStorage implements Storage using Amazon DynamoDB.

This is the recommended storage backend for production deployments. If AutoCreate is enabled in StorageOption, the table will be created automatically if it doesn't exist.

func NewDynamoDBStorage

func NewDynamoDBStorage(ctx context.Context, cfg StorageOption) (*DynamoDBStorage, error)

NewDynamoDBStorage creates a new DynamoDB-backed storage. If cfg.AutoCreate is true and the table doesn't exist, it will be created.

func (*DynamoDBStorage) DeleteChannel

func (s *DynamoDBStorage) DeleteChannel(ctx context.Context, target *ChannelItem) error

func (*DynamoDBStorage) FindAllChannels

func (s *DynamoDBStorage) FindAllChannels(ctx context.Context) (<-chan []*ChannelItem, error)

func (*DynamoDBStorage) FindOneByChannelID

func (s *DynamoDBStorage) FindOneByChannelID(ctx context.Context, channelID string) (*ChannelItem, error)

func (*DynamoDBStorage) SaveChannel

func (s *DynamoDBStorage) SaveChannel(ctx context.Context, item *ChannelItem) error

func (*DynamoDBStorage) UpdatePageToken

func (s *DynamoDBStorage) UpdatePageToken(ctx context.Context, target *ChannelItem) error

type EventBridgeClient

type EventBridgeClient interface {
	PutEvents(ctx context.Context, params *eventbridge.PutEventsInput, optFns ...func(*eventbridge.Options)) (*eventbridge.PutEventsOutput, error)
}

EventBridgeClient is the interface for Amazon EventBridge operations. This is satisfied by *eventbridge.Client.

type EventBridgeNotification

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

EventBridgeNotification implements Notification using Amazon EventBridge.

Each Google Drive change is sent as a separate EventBridge event with detail-type indicating the change type (e.g., "File Changed", "File Removed").

func (*EventBridgeNotification) SendChanges

func (n *EventBridgeNotification) SendChanges(ctx context.Context, item *ChannelItem, details []*gdnotifyevent.Detail) error

type ExprOrBool added in v0.6.0

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

ExprOrBool holds either a CEL bool expression or a static bool value.

func (*ExprOrBool) Bind added in v0.6.0

func (e *ExprOrBool) Bind(env *CELEnv) error

Bind compiles the expression if valid, otherwise parses as a static bool. When it's an expression, validates it against all validation patterns to ensure it evaluates correctly.

func (*ExprOrBool) Eval added in v0.6.0

func (e *ExprOrBool) Eval(env *CELEnv, detail *gdnotifyevent.Detail) (bool, error)

Eval evaluates the expression or returns the static value.

func (*ExprOrBool) IsExpr added in v0.6.0

func (e *ExprOrBool) IsExpr() bool

IsExpr returns true if this holds an expression.

func (*ExprOrBool) Raw added in v0.6.0

func (e *ExprOrBool) Raw() string

Raw returns the raw string value.

func (*ExprOrBool) UnmarshalYAML added in v0.6.0

func (e *ExprOrBool) UnmarshalYAML(data []byte) error

UnmarshalYAML implements yaml.Unmarshaler.

type ExprOrString added in v0.6.0

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

ExprOrString holds either a CEL string expression or a static string value.

func (*ExprOrString) Bind added in v0.6.0

func (e *ExprOrString) Bind(env *CELEnv) error

Bind compiles the expression if valid, otherwise treats it as a static value. When it's an expression, validates it against all validation patterns to ensure it evaluates correctly.

func (*ExprOrString) Eval added in v0.6.0

func (e *ExprOrString) Eval(env *CELEnv, detail *gdnotifyevent.Detail) (string, error)

Eval evaluates the expression or returns the static value.

func (*ExprOrString) IsExpr added in v0.6.0

func (e *ExprOrString) IsExpr() bool

IsExpr returns true if this holds an expression.

func (*ExprOrString) Raw added in v0.6.0

func (e *ExprOrString) Raw() string

Raw returns the raw string value.

func (*ExprOrString) UnmarshalYAML added in v0.6.0

func (e *ExprOrString) UnmarshalYAML(data []byte) error

UnmarshalYAML implements yaml.Unmarshaler.

type FileNotification

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

FileNotification implements Notification by writing events to a local JSON file.

This is suitable for development and debugging. Events are appended to the file as newline-delimited JSON (NDJSON format).

func NewFileNotification

func NewFileNotification(_ context.Context, cfg NotificationOption) (*FileNotification, error)

NewFileNotification creates a new file-based notification writer.

func (*FileNotification) SendChanges

func (n *FileNotification) SendChanges(ctx context.Context, _ *ChannelItem, details []*gdnotifyevent.Detail) error

type FileStorage

type FileStorage struct {
	Items []*ChannelItem

	LockFile string
	FilePath string
	// contains filtered or unexported fields
}

FileStorage implements Storage using local file storage.

This storage backend is suitable for development and testing. It uses file locking to ensure safe concurrent access.

func NewFileStorage

func NewFileStorage(_ context.Context, cfg StorageOption) (*FileStorage, error)

NewFileStorage creates a new file-based storage. Data is persisted to cfg.DataFile using gob encoding.

func (*FileStorage) DeleteChannel

func (s *FileStorage) DeleteChannel(ctx context.Context, target *ChannelItem) error

func (*FileStorage) FindAllChannels

func (s *FileStorage) FindAllChannels(ctx context.Context) (<-chan []*ChannelItem, error)

func (*FileStorage) FindOneByChannelID

func (s *FileStorage) FindOneByChannelID(ctx context.Context, channelID string) (*ChannelItem, error)

func (*FileStorage) SaveChannel

func (s *FileStorage) SaveChannel(ctx context.Context, item *ChannelItem) error

func (*FileStorage) UpdatePageToken

func (s *FileStorage) UpdatePageToken(ctx context.Context, target *ChannelItem) error

type ListOption added in v0.5.0

type ListOption struct {
	Output io.Writer `kong:"-"`
}

ListOption contains options for the list command.

type Notification

type Notification interface {
	// SendChanges delivers a batch of change events for the given channel.
	SendChanges(context.Context, *ChannelItem, []*gdnotifyevent.Detail) error
}

Notification defines the interface for delivering change events to downstream systems.

func NewEventBridgeNotification

func NewEventBridgeNotification(_ context.Context, cfg NotificationOption) (Notification, error)

NewEventBridgeNotification creates a new EventBridge-based notification sender.

func NewNotification

func NewNotification(ctx context.Context, cfg NotificationOption) (Notification, error)

NewNotification creates a Notification implementation based on the configuration type. Returns EventBridgeNotification for "eventbridge" or FileNotification for "file".

type NotificationOption added in v0.5.0

type NotificationOption struct {
	Type      string `help:"notification type" default:"eventbridge" enum:"eventbridge,file" env:"GDNOTIFY_NOTIFICATION_TYPE"`
	EventBus  string `help:"event bus name (eventbridge type only)" default:"default" env:"GDNOTIFY_EVENTBRIDGE_EVENT_BUS"`
	EventFile string `help:"event file path (file type only)" default:"gdnotify.json" env:"GDNOTIFY_EVENT_FILE"`
}

NotificationOption contains configuration for change event delivery.

Supported notification types:

  • "eventbridge": Sends events to Amazon EventBridge (default, recommended for production)
  • "file": Writes events to a local JSON file (suitable for development)

type S3Copier added in v0.6.0

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

S3Copier copies files from Google Drive to S3 based on configuration rules.

func NewS3Copier added in v0.6.0

func NewS3Copier(config *S3CopyConfig, env *CELEnv, driveSvc *drive.Service, awsCfg aws.Config) *S3Copier

NewS3Copier creates a new S3Copier.

func (*S3Copier) Copy added in v0.6.0

func (c *S3Copier) Copy(ctx context.Context, detail *gdnotifyevent.Detail) *CopyResult

Copy evaluates the configuration rules and copies the file to S3 if a rule matches. Returns nil if no rule matches or if the matched rule has skip=true. Removed files (change.removed=true) are always skipped. Errors are logged as warnings and do not stop execution.

type S3CopyConfig added in v0.6.0

type S3CopyConfig struct {
	BucketName ExprOrString  `yaml:"bucket_name"`
	ObjectKey  ExprOrString  `yaml:"object_key"`
	Rules      []*S3CopyRule `yaml:"rules"`
}

S3CopyConfig is the top-level configuration loaded from --s3-copy-config flag. BucketName and ObjectKey serve as defaults when rules don't specify them. These can be CEL expressions or static values.

func LoadS3CopyConfig added in v0.6.0

func LoadS3CopyConfig(path string, env *CELEnv) (*S3CopyConfig, error)

LoadS3CopyConfig loads and validates configuration from a YAML file.

func ParseS3CopyConfig added in v0.6.0

func ParseS3CopyConfig(r io.Reader, env *CELEnv) (*S3CopyConfig, error)

ParseS3CopyConfig parses and validates configuration from a reader.

func (*S3CopyConfig) Bind added in v0.6.0

func (c *S3CopyConfig) Bind(env *CELEnv) error

Bind validates and binds CEL expressions in the configuration. Rules must have a "when" expression, and non-skip rules must have bucket_name and object_key (either at top level or in the rule).

func (*S3CopyConfig) GetBucketName added in v0.6.0

func (c *S3CopyConfig) GetBucketName(env *CELEnv, rule *S3CopyRule, detail *gdnotifyevent.Detail) (string, error)

GetBucketName returns the effective bucket name for the rule. Uses the rule's bucket_name if set, otherwise falls back to config default.

func (*S3CopyConfig) GetObjectKey added in v0.6.0

func (c *S3CopyConfig) GetObjectKey(env *CELEnv, rule *S3CopyRule, detail *gdnotifyevent.Detail) (string, error)

GetObjectKey returns the effective object key for the rule. Uses the rule's object_key if set, otherwise falls back to config default.

func (*S3CopyConfig) Match added in v0.6.0

func (c *S3CopyConfig) Match(env *CELEnv, detail *gdnotifyevent.Detail) (*S3CopyRule, error)

Match finds the first matching rule for the given detail and returns it. Returns nil if no rule matches.

type S3CopyResult added in v0.6.0

type S3CopyResult struct {
	S3URI       string    `json:"s3Uri"`
	ContentType string    `json:"contentType"`
	Size        int64     `json:"size"`
	CopiedAt    time.Time `json:"copiedAt"`
}

S3CopyResult is included in the EventBridge notification payload when a file is successfully copied to S3.

type S3CopyRule added in v0.6.0

type S3CopyRule struct {
	When       ExprOrBool   `yaml:"when"`
	Skip       bool         `yaml:"skip,omitempty"`
	Export     string       `yaml:"export,omitempty"`
	BucketName ExprOrString `yaml:"bucket_name,omitempty"`
	ObjectKey  ExprOrString `yaml:"object_key,omitempty"`
}

S3CopyRule defines when and how to copy a file to S3. When is a CEL expression that determines if this rule matches. If Skip is true, matching files are not copied. Export specifies the format for Google Workspace files (e.g., "pdf", "xlsx").

type S3Uploader added in v0.6.0

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

S3Uploader handles file uploads to Amazon S3.

func NewS3Uploader added in v0.6.0

func NewS3Uploader(cfg aws.Config) *S3Uploader

NewS3Uploader creates a new S3Uploader with the given AWS config.

func (*S3Uploader) Upload added in v0.6.0

func (u *S3Uploader) Upload(ctx context.Context, input *UploadInput) (*UploadOutput, error)

Upload uploads data to S3 and returns the S3 URI.

type ServeOption added in v0.5.0

type ServeOption struct {
	Port int `help:"webhook httpd port" default:"25254" env:"GDNOTIFY_PORT"`
}

ServeOption contains options for the serve command.

type Storage

type Storage interface {
	// FindAllChannels returns a channel that yields batches of all stored channels.
	FindAllChannels(context.Context) (<-chan []*ChannelItem, error)
	// FindOneByChannelID retrieves a single channel by its ID.
	FindOneByChannelID(context.Context, string) (*ChannelItem, error)
	// UpdatePageToken updates the page token for an existing channel.
	UpdatePageToken(context.Context, *ChannelItem) error
	// SaveChannel creates or updates a channel.
	SaveChannel(context.Context, *ChannelItem) error
	// DeleteChannel removes a channel from storage.
	DeleteChannel(context.Context, *ChannelItem) error
}

Storage defines the interface for persisting notification channel state.

Implementations must be safe for concurrent access.

func NewStorage

func NewStorage(ctx context.Context, cfg StorageOption) (Storage, error)

NewStorage creates a Storage implementation based on the configuration type. Returns DynamoDBStorage for "dynamodb" or FileStorage for "file".

type StorageOption added in v0.5.0

type StorageOption struct {
	Type             string `help:"storage type" default:"dynamodb" enum:"dynamodb,file" env:"GDNOTIFY_STORAGE_TYPE"`
	TableName        string `help:"dynamodb table name" default:"gdnotify" env:"GDNOTIFY_DDB_TABLE_NAME"`
	AutoCreate       bool   `help:"auto create dynamodb table" default:"false" env:"GDNOTIFY_DDB_AUTO_CREATE" negatable:""`
	DynamoDBEndpoint string `help:"dynamodb endpoint" env:"GDNOTIFY_DDB_ENDPOINT"`
	DataFile         string `help:"file storage data file" default:"gdnotify.dat" env:"GDNOTIFY_FILE_STORAGE_DATA_FILE"`
	LockFile         string `help:"file storage lock file" default:"gdnotify.lock" env:"GDNOTIFY_FILE_STORAGE_LOCK_FILE"`
}

StorageOption contains configuration for channel state storage.

Supported storage types:

  • "dynamodb": Uses Amazon DynamoDB (default, recommended for production)
  • "file": Uses local file storage (suitable for development)

type StringExpression added in v0.6.0

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

StringExpression represents a compiled CEL expression that returns a string.

func (*StringExpression) Eval added in v0.6.0

func (s *StringExpression) Eval(detail *gdnotifyevent.Detail) (string, error)

Eval evaluates the string expression against the given detail.

type SyncOption added in v0.5.0

type SyncOption struct {
}

SyncOption contains options for the sync command.

type UploadInput added in v0.6.0

type UploadInput struct {
	Bucket      string
	Key         string
	Body        io.Reader
	ContentType string
}

UploadInput contains parameters for uploading a file to S3.

type UploadOutput added in v0.6.0

type UploadOutput struct {
	S3URI string
	Size  int64
}

UploadOutput contains the result of an upload operation.

type ValidateOption added in v0.6.0

type ValidateOption struct {
	S3CopyConfig string `arg:"" name:"config-file" optional:"" help:"path to S3 copy configuration file (overrides --s3-copy-config)"`
}

ValidateOption contains options for the validate command.

Directories

Path Synopsis
cmd
gdnotify command
pkg
gdnotifyevent
Package gdnotifyevent provides types for gdnotify EventBridge event payloads.
Package gdnotifyevent provides types for gdnotify EventBridge event payloads.

Jump to

Keyboard shortcuts

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