Beispiel #1
0
// RestoreGatewayApp restores the Gateway App
func (m *Mapper) RestoreGatewayApp() error {
	// return err when current state of gateway app is not WaitingRestore
	if err := m.StateTable.CheckGatewayState(state.WaitingRestore); err != nil {
		return state.ErrNotWaitingRestore
	}

	if err := m.StateTable.ChangeGatewayState(state.Restoring,
		common.ToLocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID)); err != nil {
		return err
	}

	// change back to WaitingRestore only err happened during restoring gateway app
	hanleErr := func(err error) error {
		m.StateTable.ChangeGatewayState(state.WaitingRestore,
			common.ToLocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID))
		return err
	}

	// disconnect all connecting mqtt clients
	m.Cloud.DisconnectAllMQTTClients()
	// clear DB
	if err := m.Store.ClearDB(); err != nil {
		return hanleErr(err)
	}

	// onboard with gateway app
	if _, err := m.onboardgatewayApp(); err != nil {
		return hanleErr(err)
	}

	// restore gateway
	if err := m.restoreGateway(m.Config.MasterApp.Site, m.Config.MasterApp.AppID); err != nil {
		return hanleErr(err)
	}

	// change state of gateway app to DoneOnboard after restore
	if err := m.StateTable.ChangeGatewayState(state.DoneOnboard,
		common.ToLocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID)); err != nil {
		return hanleErr(err)
	}

	// Restore all the end-node apps saved on cloud
	apps, err := m.ListAllEndnodeApps()
	if err != nil {
		return err
	}
	for _, a := range apps {
		m.StateTable.ChangeAppState(state.Restoring, common.LocalID(common.LocalAppID(a.ServerLocation, a.AppID)))
		err = m.RestoreEndnodeApp(a)
		if err != nil {
			return err
		}
		m.StateTable.ChangeAppState(state.DoneOnboard, common.LocalID(common.LocalAppID(a.ServerLocation, a.AppID)))
	}

	//change restoreMode to false
	m.StateTable.RestoreMode = false
	return nil
}
Beispiel #2
0
// PendingEndnodes returns pending (not mapped to cloud) end-nodes.
func (m *Mapper) PendingEndnodes(serverLocation, appID string) ([]common.PendingEndnode, error) {
	//verify state
	if err := m.gatewayRestoringOrNotReady(); err != nil {
		return []common.PendingEndnode{}, err
	}

	// check whether gateway id exists
	if _, err := m.Store.FindGatewayByAppID(appID); err != nil {
		return []common.PendingEndnode{}, err
	}

	if err := m.StateTable.CheckAppState(common.ToLocalAppID(serverLocation, appID), state.DoneOnboard); err != nil {
		return []common.PendingEndnode{}, state.ErrNotOnboarded
	}

	items, err := m.Store.FindNilCloud(serverLocation, appID)
	if err != nil {
		return nil, err
	}
	endnodes := make([]common.PendingEndnode, 0, len(items))
	for _, o := range items {
		endnodes = append(endnodes, common.PendingEndnode{
			VendorThingID:   o.EndnodeAddress.VendorThingID,
			ThingProperties: m.toJSON(o.ThingProperties),
			States:          m.toJSON(o.States),
		})
	}
	return endnodes, nil
}
Beispiel #3
0
// GetGatewayID gets the Gateway's ThingID for that app.
func (m *Mapper) GetGatewayID(serverLocation, appID string) (string, error) {
	// verify state first
	if err := m.gatewayRestoringOrNotReady(); err != nil {
		return "", err
	}

	gca, err := m.Store.FindGatewayByAppID(appID)
	if err != nil {
		return "", err
	}

	if err := m.StateTable.CheckAppState(common.ToLocalAppID(serverLocation, appID), state.DoneOnboard); err != nil {
		return "", state.ErrNotOnboarded
	}
	return gca.ThingID, nil
}
Beispiel #4
0
// CompleteEndnodeOnboarding notifies Endnode onboarding completion to the Gateway
func (m *Mapper) CompleteEndnodeOnboarding(serverLocation, appID, vendorThingID, thingID string) error {
	//verify state
	if err := m.gatewayRestoringOrNotReady(); err != nil {
		return err
	}
	// check whether gateway id exists
	if _, err := m.Store.FindGatewayByAppID(appID); err != nil {
		return err
	}
	if err := m.StateTable.CheckAppState(common.ToLocalAppID(serverLocation, appID), state.DoneOnboard); err != nil {
		return state.ErrNotOnboarded
	}

	ea := common.EndnodeAddress{
		ServerLocation: serverLocation,
		AppID:          appID,
		VendorThingID:  vendorThingID,
	}
	ca := common.CloudAddress{
		ServerLocation: serverLocation,
		AppID:          appID,
		ThingID:        thingID,
	}
	item, err := m.Store.UpdateCloud(ea, ca)
	if err != nil {
		return err
	}
	// update endnode token
	gca, err := m.Store.FindGatewayByAppID(appID)
	if err != nil {
		return err
	}
	err = m.Cloud.GenerateEndnodeToken(ca, gca)
	if err != nil {
		return err
	}

	// update state
	return m.Cloud.SendState(*item.CloudAddress, item.States)
}
Beispiel #5
0
// ReplaceEndnode update exsiting Thing with new vendorThingID
func (m *Mapper) ReplaceEndnode(serverLocation, appID, newVendorThingID, thingID string) error {
	//verify state
	if err := m.gatewayRestoringOrNotReady(); err != nil {
		return err
	}
	// check whether gateway id exists
	if _, err := m.Store.FindGatewayByAppID(appID); err != nil {
		return err
	}
	if err := m.StateTable.CheckAppState(common.ToLocalAppID(serverLocation, appID), state.DoneOnboard); err != nil {
		return state.ErrNotOnboarded
	}

	ea := common.EndnodeAddress{
		ServerLocation: serverLocation,
		AppID:          appID,
		VendorThingID:  newVendorThingID,
	}
	ca := common.CloudAddress{
		ServerLocation: serverLocation,
		AppID:          appID,
		ThingID:        thingID,
	}

	// endnode address before updated
	oea, err := m.Store.FindByCloudAddress(ca)
	if err != nil {
		return err
	}

	_, err = m.Store.UpdateEndnode(ea, ca)
	if err != nil {
		return err
	}

	// update converter-endnode mapping
	return m.Endnode.ReplaceEndnode(*oea.EndnodeAddress, ea)
}
Beispiel #6
0
// Run starts gateway-agent core procedure.
// When restore is true, gateway-agent start as restore mode, then go to normal
// mode.
func Run(c *config.Config, restore bool) error {
	if !atomic.CompareAndSwapInt32(&running, 0, 1) {
		return errors.New("agent already running")
	}
	debug.Printf("Config: %#v\n", *c)

	// build asynchronous objects.
	quit = make(chan int)
	wait = &sync.WaitGroup{}

	// setup data store
	store, err := store.New(c.Store.Type, c.Store.Params)
	if err != nil {
		atomic.StoreInt32(&running, 0)
		return err
	}
	defer store.Close()

	// setup global context.
	g := common.Global{
		Config: *c,
		Log:    log.New(c.LogWriter(), "IoTGW ", log.Ltime),
		Quit:   quit,
		Wait:   wait,
	}

	st, err := state.LoadTable(store,
		common.ToLocalAppID(g.Config.MasterApp.Site, g.Config.MasterApp.AppID),
		restore)
	if err != nil {
		atomic.StoreInt32(&running, 0)
		return err
	}

	// prepare all inner-processes.
	mapper := &mapper.Mapper{
		Global: g,
		Store:  store,

		StateTable: st,
	}
	cg := &cloud.Gateway{
		Global: g,
		Mapper: mapper,
		Store:  store,
	}
	eg := &endnode.Gateway{
		Global: g,
		Mapper: mapper,
	}
	local := &local.Server{
		Global: g,
		Addr:   c.LocalServer.Addr.NetworkAddress(),
		Mapper: mapper,
		Store:  store,
	}
	ad := &advertise.Advertiser{
		Global: g,
		Location: advertise.Location{
			HTTPS: false,
			Port:  c.LocalServer.Addr.Port,
			Path:  "",
		},
		Server: fmt.Sprintf("%s UPnP/1.1 gateway-agent", runtime.GOOS),
	}

	// connect inner-processes.
	mapper.Cloud = cg
	mapper.Endnode = eg

	// start all inner-processes.
	mapper.Run()
	cg.Run()
	eg.Run()
	local.Run()
	ad.Run()
	atomic.StoreInt32(&running, 2)

	// detect termination.
	mw := c.MessageWriter()
	fmt.Fprintln(mw, "Press CTRL-C to terminate")
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT)
MainLoop:
	for {
		select {
		case <-quit:
			break MainLoop
		case s := <-sig:
			switch s {
			case syscall.SIGINT:
				stop()
				break MainLoop
			}
		}
	}
	signal.Stop(sig)

	wait.Wait()
	atomic.StoreInt32(&running, 0)
	fmt.Fprintln(mw, "Teminated completely")
	return nil
}
Beispiel #7
0
// OnboardGatewayApp onboards the Gateway for the Gateway App
func (m *Mapper) OnboardGatewayApp() (string, error) {
	// verify state
	if m.StateTable.RestoreMode {
		return "", state.ErrRestoringGateway
	}
	if err := m.StateTable.CheckGatewayState(state.Onboarding); err == nil {
		return "", state.ErrOnboarding
	}

	// start to onboard
	// change state to Onboarding before onboard
	if err := m.StateTable.ChangeGatewayState(state.Onboarding,
		common.ToLocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID)); err != nil {
		return "", err
	}

	// change state of gateway app to onboarding before onboard
	gwLocalID := common.LocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID)
	if err := m.StateTable.ChangeAppState(state.Onboarding,
		common.LocalID(gwLocalID)); err != nil {
		return "", err
	}

	handleErr := func(err error) (string, error) {
		m.StateTable.ChangeGatewayState(state.WaitingOnboard, common.ToLocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID))
		m.StateTable.ChangeAppState(state.Onboarding,
			common.LocalID(gwLocalID))
		return "", err
	}

	// for multiple onboard, need to delete gateway from DB first
	if _, err := m.Store.FindGatewayByAppID(m.Config.MasterApp.AppID); err == nil {

		// disconnect mqtt connection
		if err := m.Cloud.DisconnectMQTTClient(common.App{
			AppID:          m.Config.MasterApp.AppID,
			ServerLocation: m.Config.MasterApp.Site,
		}); err != nil {
			return handleErr(err)
		}

		// delete gateway
		if err := m.Store.DeleteGateway(m.Config.MasterApp.AppID); err != nil {
			return handleErr(err)
		}
	}

	gwID, err := m.onboardgatewayApp()
	if err != nil {
		return handleErr(err)
	}

	// change state of gateway app to DoneOnboard after onboard
	if err := m.StateTable.ChangeAppState(state.DoneOnboard, common.LocalID(gwLocalID)); err != nil {
		return handleErr(err)
	}

	// change state to DoneOnboard after onboard
	if err := m.StateTable.ChangeGatewayState(state.DoneOnboard,
		common.ToLocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID)); err != nil {
		return handleErr(err)
	}

	return gwID, nil
}