/* sendOutstandingRequest sends all request messages for update messages that have not yet been applied. This ensures that no files are missed and the bootstrap successfully completes. */ func (c *chaninterface) sendOutstandingRequest(address string) { // if no address given nothing to do so return immediately if address == "" { return } // lock and unlock map access for this function c.mutex.Lock() defer func() { c.mutex.Unlock() }() // determine messages available amount := len(c.messages) // if all have been applied this method can stop if amount == 0 { log.Println("WARNING: nothing to request!") return } // send requests log.Println("Requesting", amount, "files.") for _, um := range c.messages { // make sure we don't request directories if um.Object.Directory { log.Println("WARNING: trying to request directory, ignoring!") continue } // prepare request file rm := shared.CreateRequestMessage(shared.OtObject, um.Object.Identification) // send request file c.boot.channel.Send(address, rm.JSON()) } }
/* handlePushMessage handles the logic upon receiving a PushMessage. */ func (c *chaninterface) handlePushMessage(address string, pm *shared.PushMessage) { // note that file transfer is allowed for when file is received key := c.buildKey(address, pm.Identification) // if we reach this, allow and store push message too c.mutex.Lock() c.allowedTransfers[key] = *pm c.mutex.Unlock() log.Println("Receiving", pm.Identification) // notify that we have received the push message rm := shared.CreateRequestMessage(pm.ObjType, pm.Identification) c.enc.channel.Send(address, rm.JSON()) }
/* Run is the background thread that keeps checking if it can bootstrap. */ func (b *Bootstrap) run() { defer func() { log.Println("Bootstrap:", "Background process stopped.") }() waitTicker := time.Tick(tickSpanNone) for { select { case <-b.stop: b.wg.Done() return case <-waitTicker: addresses, err := b.channel.OnlineAddresses() if err != nil { log.Println("Check:", err) break } if len(addresses) == 0 { log.Println("None available yet.") break } if len(addresses) > 1 { // since we'll always only try connecting to one, warn specifically! log.Println("WARNING: Multiple online! Will try connecting to ", addresses[0][:8], " only.") } // if not trusted, we are done once the connection has been accepted. if !b.IsTrusted() { // execute callback b.done() // stop bg thread b.stop <- false // go quit continue } log.Println("Initiating transfer of directory state.") // yo, we want to bootstrap! rm := shared.CreateRequestMessage(shared.OtModel, shared.IDMODEL) b.channel.Send(addresses[0], rm.JSON()) } // select } // for }
func (c *chaninterface) OnMessage(address, message string) { // check if lock message, or request, or send message v := &shared.Message{} err := json.Unmarshal([]byte(message), v) if err == nil { // special case for lock messages (can be received if not locked) if v.Type == shared.MsgLock { msg := &shared.LockMessage{} err := json.Unmarshal([]byte(message), msg) if err != nil { log.Println("OnMessage: failed to parse JSON!", err) return } c.handleLockMessage(address, msg) return } // for all others ensure that we are locked correctly if !c.enc.checkLock(address) { // if not warn and ignore message log.Println("OnMessage: not locked to given address!", address[:8]) // TODO send notify that they are unlocked back? return } // if correctly locked handle message according to type switch msgType := v.Type; msgType { case shared.MsgRequest: msg := &shared.RequestMessage{} err := json.Unmarshal([]byte(message), msg) if err != nil { log.Println("OnMessage: failed to parse JSON!", err) return } c.handleRequestMessage(address, msg) case shared.MsgPush: msg := &shared.PushMessage{} err := json.Unmarshal([]byte(message), msg) if err != nil { log.Println("OnMessage: failed to parse JSON!", err) return } c.handlePushMessage(address, msg) case shared.MsgNotify: msg := &shared.NotifyMessage{} err := json.Unmarshal([]byte(message), msg) if err != nil { log.Println("OnMessage: failed to parse JSON!", err) return } c.handleNotifyMessage(address, msg) default: log.Println("OnMessage: WARNING: Unknown object received:", msgType.String()) } // in any case return as we are done handling them return } // if unmarshal didn't work check for plain commands: // TODO these are temporary until it works, remove them later switch message { case "push": log.Println("Sending example push message.") pm := shared.CreatePushMessage("ID_HERE", shared.OtObject) c.enc.channel.Send(address, pm.JSON()) case "lock": log.Println("Sending example lock message.") lm := shared.CreateLockMessage(shared.LoRequest) c.enc.channel.Send(address, lm.JSON()) case "unlock": log.Println("Sending example unlock message.") lm := shared.CreateLockMessage(shared.LoRelease) c.enc.channel.Send(address, lm.JSON()) case "request": log.Println("Sending example request message.") rm := shared.CreateRequestMessage(shared.OtObject, "ID_HERE") c.enc.channel.Send(address, rm.JSON()) default: log.Println("Received:", message) c.enc.channel.Send(address, "Received non JSON message.") } }