func (c *client) start() { if !config.IsPaired() { log.Infof("Client is unpaired. Attempting to pair.") if err := c.pair(); err != nil { log.Fatalf("An error occurred while pairing. Restarting. error: %s", err) } log.Infof("Pairing was successful.") // We reload the config so the creds can be picked up config.MustRefresh() if !config.IsPaired() { log.Fatalf("Pairing appeared successful, but I did not get the credentials. Restarting.") } } log.Infof("Client is paired. User: %s", config.MustString("userId")) if !config.NoCloud() { mesh, err := refreshMeshInfo() if err == errorUnauthorised { log.Warningf("UNAUTHORISED! Unpairing.") c.unpair() return } if err != nil { log.Warningf("Failed to refresh mesh info: %s", err) } else { log.Debugf("Got mesh info: %+v", mesh) } config.MustRefresh() if !config.HasString("masterNodeId") { log.Warningf("We don't have any mesh information. Which is unlikely. But we can't do anything without it, so restarting client.") time.Sleep(time.Second * 10) os.Exit(0) } } if config.MustString("masterNodeId") == config.Serial() { log.Infof("I am the master, starting HomeCloud.") cmd := exec.Command("start", "sphere-homecloud") cmd.Output() go c.exportNodeDevice() c.master = true } else { log.Infof("I am a slave. The master is %s", config.MustString("masterNodeId")) // TODO: Remove this when we are running drivers on slaves cmd := exec.Command("stop", "sphere-director") cmd.Output() c.masterReceiveTimeout = time.AfterFunc(orphanTimeout, func() { c.setOrphaned() }) } go func() { log.Infof("Starting search for peers") for { c.findPeers() time.Sleep(time.Second * 30) } }() }
func (m *baseModel) Sync(timeout time.Duration, conn redis.Conn) error { m.syncing.Wait() m.syncing.Add(1) defer m.syncing.Done() if config.NoCloud() { m.log.Infof("sync: syncing disabled because there is no cloud") return nil } m.log.Infof("sync: Syncing %ss. Save data from cloud?:%s", m.idType, enableSyncFromCloud) var diffList SyncDifferenceList manifest, err := m.getSyncManifest(conn) if err != nil { return err } m.log.Debugf("sync: Sending %d %s local update times", len(*manifest), m.idType) calcClient := m.SyncConn.Conn.GetServiceClient("$ninja/services/rpc/modelstore/calculate_sync_items") err = calcClient.Call("modelstore.calculate_sync_items", []interface{}{m.idType, manifest}, &diffList, timeout) if err != nil { return fmt.Errorf("Failed calling calculate_sync_items for model %s error:%s", m.idType, err) } m.log.Infof("sync: Cloud requires %d %s(s), Node requires %d %s(s)", len(diffList.CloudRequires), m.idType, len(diffList.NodeRequires), m.idType) if len(diffList.CloudRequires)+len(diffList.NodeRequires) == 0 { // Nothing to do, we're in sync. return nil } requestIds := make([]string, 0) for id := range diffList.NodeRequires { requestIds = append(requestIds, id) } requestedData := SyncDataSet{} for id := range diffList.CloudRequires { obj := reflect.New(m.objType).Interface() err = m.fetch(id, obj, true, conn) if err != nil && err != RecordNotFound { return fmt.Errorf("Failed retrieving requested %s id:%s error:%s", m.idType, id, err) } if err == RecordNotFound { obj = nil } lastUpdated, err := m.getLastUpdated(id, conn) if err != nil { return fmt.Errorf("Failed retrieving last updated time for requested %s id:%s error:%s", m.idType, id, err) } requestedData[id] = SyncObject{obj, lastUpdated.UnixNano() / int64(time.Millisecond)} } if deleteUnknownFromCloud { for id := range diffList.NodeRequires { if _, ok := (*manifest)[id]; !ok { // We've never heard of this, so remove it m.log.Infof("Removing %s id:%s from cloud.", m.idType, id) requestedData[id] = SyncObject{nil, time.Now().UnixNano() / int64(time.Millisecond)} } } } syncClient := m.SyncConn.Conn.GetServiceClient("$ninja/services/rpc/modelstore/do_sync_items") var syncReply SyncReply err = syncClient.Call("modelstore.do_sync_items", []interface{}{m.idType, requestedData, requestIds}, &syncReply, timeout) if err != nil { return fmt.Errorf("Failed calling do_sync_items for model %s error:%s", m.idType, err) } defer syncFS() if enableSyncFromCloud { for id, requestedObj := range syncReply.RequestedObjects { obj := reflect.New(m.objType).Interface() err := json.Unmarshal(requestedObj.Data, obj) if err != nil { m.log.Warningf("Failed to unmarshal requested %s id:%s error: %s", m.idType, id, err) m.delete(id, conn) } else if string(requestedObj.Data) == "null" { m.log.Infof("Requested %s id:%s has been remotely deleted", m.idType, id) m.delete(id, conn) } else { updated, err := m.save(id, obj, conn) if err != nil { return fmt.Errorf("Failed to save requested %s id:%s error: %s", m.idType, id, err) } if !updated { m.log.Warningf("We requested an updated %s id:%s but it was the same as what we had.", m.idType, id) } } err = m.markUpdated(id, time.Unix(0, requestedObj.LastModified*int64(time.Millisecond)), conn) if err != nil { m.log.Warningf("Failed to update last modified time of requested %s id:%s error: %s", m.idType, id, err) } } } else { m.log.Warningf("Ignoring sync data from cloud.") } if err != nil { ts, err := time.Now().MarshalText() if err != nil { return err } _, err = conn.Do("SET", m.idType+"s:synced", ts) } return err }