blob: d0dbf11123cbb11e0a59afa6edb08bd56db32147 [file] [log] [blame]
// Copyright 2017 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 ipcserver
import (
"fmt"
"strings"
"sync"
"fidl/amber"
"fidl/bindings"
"amber/daemon"
"amber/lg"
"amber/pkg"
"syscall/zx"
)
type ControlSrvr struct {
daemonGate sync.Once
daemon *daemon.Daemon
bs bindings.BindingSet
actMon *ActivationMonitor
activations chan<- string
compReqs chan<- *completeUpdateRequest
writeReqs chan<- *startUpdateRequest
sysUpdate *daemon.SystemUpdateMonitor
}
const ZXSIO_DAEMON_ERROR = zx.SignalUser0
func NewControlSrvr(d *daemon.Daemon, s *daemon.SystemUpdateMonitor) *ControlSrvr {
go bindings.Serve()
a := make(chan string, 5)
c := make(chan *completeUpdateRequest, 1)
w := make(chan *startUpdateRequest, 1)
m := NewActivationMonitor(c, w, a, daemon.WriteUpdateToPkgFS)
go m.Do()
return &ControlSrvr{
daemon: d,
actMon: m,
activations: a,
compReqs: c,
writeReqs: w,
sysUpdate: s,
}
}
func (c *ControlSrvr) DoTest(in int32) (out string, err error) {
r := fmt.Sprintf("Your number was %d\n", in)
return r, nil
}
func (c *ControlSrvr) AddSrc(cfg amber.SourceConfig) (bool, error) {
if err := c.daemon.AddTUFSource(&cfg); err != nil {
return false, err
}
return true, nil
}
func (c *ControlSrvr) CheckForSystemUpdate() (bool, error) {
if c.sysUpdate != nil {
c.sysUpdate.Check()
return true, nil
}
return false, nil
}
func (c *ControlSrvr) RemoveSrc(url string) (bool, error) {
return true, nil
}
func (c *ControlSrvr) Check() (bool, error) {
return true, nil
}
func (c *ControlSrvr) ListSrcs() ([]amber.SourceConfig, error) {
m := c.daemon.GetSources()
v := make([]amber.SourceConfig, 0, len(m))
for _, src := range m {
v = append(v, *src.GetConfig())
}
return v, nil
}
func (c *ControlSrvr) getAndWaitForUpdate(name string, version, merkle *string, ch *zx.Channel) {
res, err := c.downloadPkgMeta(name, version, merkle)
if err != nil {
signalErr := ch.Handle().SignalPeer(0, zx.SignalUser0)
if signalErr != nil {
lg.Log.Printf("signal failed: %s", signalErr)
ch.Close()
} else {
ch.Write([]byte(err.Error()), []zx.Handle{}, 0)
}
return
}
lg.Log.Println("Package metadata retrieved, sending for additional processing")
compReq := completeUpdateRequest{pkgData: res, replyChan: ch}
c.compReqs <- &compReq
}
func (c *ControlSrvr) GetUpdateComplete(name string, version, merkle *string) (zx.Channel, error) {
r, w, e := zx.NewChannel(0)
if e != nil {
lg.Log.Printf("Could not create channel")
return 0, e
}
go c.getAndWaitForUpdate(name, version, merkle, &w)
return r, nil
}
func (c *ControlSrvr) PackagesActivated(merkle []string) error {
for _, m := range merkle {
c.activations <- m
lg.Log.Printf("Got package activation for %s\n", m)
}
return nil
}
func (c *ControlSrvr) downloadPkgMeta(name string, version, merkle *string) (*daemon.GetResult, error) {
d := ""
if version == nil {
version = &d
}
if merkle == nil {
merkle = &d
}
if len(name) == 0 {
return nil, fmt.Errorf("No package name provided")
}
if name[0] != '/' {
name = fmt.Sprintf("/%s", name)
}
ps := pkg.NewPackageSet()
pkg := pkg.Package{Name: name, Version: *version, Merkle: *merkle}
ps.Add(&pkg)
updates := c.daemon.GetUpdates(ps)
result, ok := updates[pkg]
if !ok {
return nil, fmt.Errorf("No update available for %s", name)
}
if result.Err != nil {
return nil,
fmt.Errorf("Error while checking for update to %s: %s", result.Orig.Name,
result.Err)
}
return result, nil
}
func (c *ControlSrvr) GetUpdate(name string, version, merkle *string) (*string, error) {
result, err := c.downloadPkgMeta(name, version, merkle)
if err != nil {
return nil, err
}
wrtReq := startUpdateRequest{pkgData: result, wg: &sync.WaitGroup{}, err: nil}
wrtReq.wg.Add(1)
c.writeReqs <- &wrtReq
wrtReq.wg.Wait()
return &result.Update.Merkle, wrtReq.err
}
func (c *ControlSrvr) GetBlob(merkle string) error {
if len(strings.TrimSpace(merkle)) == 0 {
return fmt.Errorf("Supplied merkle root is empty")
}
return c.daemon.GetBlob(merkle)
}
func (c *ControlSrvr) Quit() {
c.bs.Close()
close(c.activations)
close(c.compReqs)
close(c.writeReqs)
}
func (c *ControlSrvr) Bind(ch zx.Channel) error {
s := amber.ControlStub{Impl: c}
_, err := c.bs.Add(&s, ch, nil)
return err
}
func (c *ControlSrvr) Login(srcId string) (*amber.DeviceCode, error) {
return c.daemon.Login(srcId)
}