func (this *SyncMgr) onNotify(remote int, fp *crypto.Digest, in io.Reader, out io.Writer) error { var mesgs []dataMesg err := transfer.Decode(in, &mesgs) if err != nil { return err } // Find client this.cmut.Lock() cl, ok := this.clients[fp.String()] this.cmut.Unlock() if !ok { this.Log.Printf("Receiving notify from non-friend, ignoring") } for _, mesg := range mesgs { this.Log.Printf("Received data, topic = %s, key = %s", mesg.Topic, mesg.Key) row := this.Db.SingleQuery(`SELECT heard_seqno FROM TopicFriend WHERE topic = ? AND friend_id = ? AND desired = 1`, mesg.Topic, remote) var prev_seq int if !this.Db.MaybeScan(row, &prev_seq) { continue } sink, ok := this.sinks[mesg.RecordType] if !ok || prev_seq >= mesg.Seqno { continue } sink(cl.friendId, fp, &mesg.Record) this.Db.Exec("Update TopicFriend SET heard_seqno = ? WHERE topic = ? AND friend_id = ?", mesg.Seqno, mesg.Topic, remote) } return nil }
// Reads from io.Reader and generates a new object, put it to the meta-data layer func (this *DataMgr) GetData(topic string, key string, stream io.Writer) error { data := this.Get(topic, key) if data == nil { return fmt.Errorf("Unknown key") } var objHash *crypto.Digest err := transfer.DecodeBytes(data, &objHash) if err != nil { return err } okey := objHash.String() this.lock.Lock() obj := this.maybeGetObj(okey) if obj == nil || obj.State != DSLocal { return fmt.Errorf("File not local yet") } obj.Holds++ this.writeObj(obj) this.lock.Unlock() name := path.Join(this.dir, okey) file, err := os.Open(name) if err == nil { _, err = io.Copy(stream, file) } this.lock.Lock() obj = this.getObj(okey) obj.Holds-- this.writeObj(obj) this.lock.Unlock() return err }
// Add a new friend, or if the friend exists, update the host and port data. func (this *LinkMgr) RemoveFriend(fp *crypto.Digest) { this.cmut.Lock() defer this.cmut.Unlock() fi, ok := this.friendsFp[fp.String()] if !ok { return } for _, f := range this.listeners { f(fi.id, fp, FriendRemoved) } this.Db.Exec("DELETE FROM FRIEND WHERE id = ?", fi.id) delete(this.friendsFp, fp.String()) delete(this.friendsId, fi.id) }
// Add a new friend, or if the friend exists, update the host and port data. func (this *LinkMgr) AddUpdateFriend(fp *crypto.Digest, host string, port uint16) { this.cmut.Lock() defer this.cmut.Unlock() // Make or insert friend this.Db.Exec( "INSERT OR IGNORE INTO Friend (id, fingerprint, host, port) VALUES (NULL, ?, ?, ?)", fp.Bytes(), host, port) row := this.Db.SingleQuery("SELECT id FROM Friend WHERE fingerprint = ?", fp.Bytes()) var id int this.Db.Scan(row, &id) this.Db.Exec("UPDATE Friend SET host = ?, port = ? WHERE id = ?", host, port, id) _, ok := this.friendsFp[fp.String()] fi := &friendInfo{id: id, fingerprint: fp, host: host, port: port} this.friendsFp[fp.String()] = fi this.friendsId[id] = fi if !ok { // If it was added, signal upper layer for _, f := range this.listeners { f(id, fp, FriendAdded) } } }
// Kicks off the link manager, presumes Callbacks has been set func (this *LinkMgr) Run() error { conn, err := net.Listen("tcp", this.server.Addr) if err != nil { return err } this.listener = tls.NewListener(conn, this.server.TLSConfig) rows := this.Db.MultiQuery("SELECT id, fingerprint, isgdid, host, port FROM Friend") for rows.Next() { var id int var isgdid int var fp []byte var host string var port uint16 this.Db.Scan(rows, &id, &fp, &isgdid, &host, &port) var fingerprint *crypto.Digest err := transfer.DecodeBytes(fp, &fingerprint) if err != nil { panic(err) } fi := &friendInfo{ id: id, fingerprint: fingerprint, isgdid: isgdid, host: host, port: port, } this.friendsFp[fingerprint.String()] = fi this.friendsId[id] = fi } this.cmut.RLock() for id, fi := range this.friendsId { for _, f := range this.listeners { f(id, fi.fingerprint, FriendStartup) } } this.cmut.RUnlock() this.wait.Add(1) go func() { this.server.Serve(this.listener) this.wait.Done() }() return nil }
func (this *SyncMgr) onSubscribe(id int, fp *crypto.Digest, rec *Record) { this.cmut.RLock() client, ok := this.clients[fp.String()] this.cmut.RUnlock() if !ok { return } client.lock.Lock() this.Db.Exec("INSERT OR IGNORE INTO TopicFriend (friend_id, topic) VALUES (?, ?)", client.friendId, rec.Key) enable := (rec.Value[0] != 0) this.Db.Exec("UPDATE TopicFriend SET requested = ?, acked_seqno = ? WHERE friend_id = ? AND topic = ?", enable, rec.Priority, id, rec.Key) client.wakeNotify.Broadcast() client.lock.Unlock() }
func (this *DataMgr) onMeta(topic string, key string, data []byte, fp string, isUp bool) { var objHash *crypto.Digest err := transfer.DecodeBytes(data, &objHash) if err != nil { this.Log.Printf("Unable to decode meta-data value") return } objKey := objHash.String() this.lock.Lock() defer this.lock.Unlock() obj := this.getObj(objKey) if isUp { obj.metaUp(topic) } else { obj.metaDown(topic) } this.writeObj(obj) }
// Update the subscription state for a topic on a particular friend. func (this *SyncMgr) Subscribe(id *crypto.Digest, topic string, enable bool) bool { this.cmut.RLock() client, ok := this.clients[id.String()] this.cmut.RUnlock() if !ok { return false } client.lock.Lock() this.Db.Exec("INSERT OR IGNORE INTO TopicFriend (friend_id, topic) VALUES (?, ?)", client.friendId, topic) this.Db.Exec("UPDATE TopicFriend SET desired = ? WHERE friend_id = ? AND topic = ?", enable, client.friendId, topic) row := this.Db.SingleQuery("SELECT heard_seqno FROM TopicFriend WHERE friend_id = ? AND topic = ?", client.friendId, topic) var heard int this.Db.Scan(row, &heard) enbyte := byte(0) if enable { enbyte = 1 } myFp := this.Ident.Public().Fingerprint() client.lock.Unlock() this.Put(&Record{ RecordType: RTSubscribe, Topic: crypto.HashOf(myFp, id).String(), Key: topic, Value: []byte{enbyte}, Priority: heard, Author: "$", }) return true }
func (this *SyncMgr) onFriendChange(id int, fp *crypto.Digest, what link.FriendStatus) { this.cmut.Lock() if what == link.FriendStartup || what == link.FriendAdded { this.Log.Printf("Adding friend: %s", fp.String()) myFp := this.Ident.Public().Fingerprint() this.Db.Exec("INSERT OR IGNORE INTO TopicFriend (topic, friend_id, desired, requested) VALUES (?, ?, ?, ?)", crypto.HashOf(fp, myFp).String(), id, 1, 1) this.Db.Exec("INSERT OR IGNORE INTO TopicFriend (topic, friend_id, desired, requested) VALUES (?, ?, ?, ?)", crypto.HashOf(myFp, fp).String(), id, 1, 1) cl := newClientLooper(this, id) this.clients[fp.String()] = cl cl.run() } else { cl := this.clients[fp.String()] cl.stop() delete(this.clients, fp.String()) this.Db.Exec("DELETE INTO TopicFriend WHERE friend_id = ?", id) } this.cmut.Unlock() }
func (this *ApiMgr) populateFriend(json *FriendJson, myFp, fp *crypto.Digest) { json.Id = fp.String() json.SelfCid = crypto.HashOf(fp, fp).String() json.SendCid = crypto.HashOf(myFp, fp).String() json.RecvCid = crypto.HashOf(fp, myFp).String() }
func (this *TestNode) OnFriendChange(id int, fingerprint *crypto.Digest, what FriendStatus) { this.Log.Printf("OnFriendChange(%d, %s, %d)", id, fingerprint.String(), what) }