blob: 7136401111b7e53a2c05a1014d8c92676503825f [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package amber
import (
"context"
"fmt"
"net/http"
"path"
)
// DefaultServerAddress is the default address to serve packages from.
const DefaultServerAddress = "localhost:8083"
// DefaultPackagesPath returns the default path to an amber package repository within a
// Fuchsia build directory.
func DefaultPackagesPath(buildDir string) string {
return path.Join(buildDir, "amber-files", "repository")
}
// Middleware creates a new http.Handler that executes itself before executing next. The
// new handler should always call next to give the server a chance to serve files.
type Middleware func(next http.Handler) http.Handler
// ServerOptions specify how to serve a package repository.
type ServerOptions struct {
// Address is the HTTP address to serve from
Address string
// PackagesPath is the path to the package repository to serve.
PackagesPath string
// Middleware is optional HTTP middleware to use for the Server. This will be called
// on every incoming request before the server handles the message.
Middleware Middleware
}
// ServePackages starts an OTA server for the amber repository located at path. Address
// is the HTTP address to serve from. This function will block until the server is done.
// The server will exit when the provide context is done. Returns the string URL of the
// package server.
func ServePackages(ctx context.Context, opts ServerOptions) (url string) {
handler := http.FileServer(http.Dir(opts.PackagesPath))
if opts.Middleware != nil {
handler = opts.Middleware(handler)
}
s := &server{
address: opts.Address,
handler: handler,
}
s.delegate = &http.Server{
Addr: opts.Address,
Handler: s.handler,
}
go s.start(ctx)
return s.url()
}
// server is a handle to a package repository server.
type server struct {
address string
delegate *http.Server
handler http.Handler
}
func (s *server) url() string {
return fmt.Sprintf("http://%s", s.address)
}
func (s *server) start(ctx context.Context) error {
errors := make(chan error)
go func() {
errors <- s.delegate.ListenAndServe()
}()
select {
case <-ctx.Done():
if err := s.delegate.Close(); err != nil {
return err
}
return ctx.Err()
case err := <-errors:
return err
}
}