github.com/attic-labs/noms@v0.0.0-20210827224422-e5fa29d95e8b/samples/go/decent/lib/pubsub.go (about) 1 // See: https://github.com/attic-labs/noms/issues/3808 2 // +build ignore 3 4 // Copyright 2017 Attic Labs, Inc. All rights reserved. 5 // Licensed under the Apache License, version 2.0: 6 // http://www.apache.org/licenses/LICENSE-2.0 7 8 package lib 9 10 import ( 11 "context" 12 "encoding/json" 13 "sync" 14 15 "github.com/attic-labs/noms/go/d" 16 "github.com/attic-labs/noms/go/hash" 17 "github.com/attic-labs/noms/samples/go/decent/dbg" 18 "github.com/ipfs/go-ipfs/core" 19 "github.com/mr-tron/base58/base58" 20 ) 21 22 var ( 23 PubsubUser = "default" 24 seenHash = map[hash.Hash]bool{} 25 seenHashMutex = sync.Mutex{} 26 ) 27 28 func lockSeenF() func() { 29 seenHashMutex.Lock() 30 return func() { 31 seenHashMutex.Unlock() 32 } 33 } 34 35 // RecieveMessages listens for messages sent by other chat nodes. It filters out 36 // any msgs that have already been received and adds events to teh events channel 37 // for any msgs that it hasn't seen yet. 38 func ReceiveMessages(node *core.IpfsNode, events chan ChatEvent, cInfo ClientInfo) { 39 sub, err := node.Floodsub.Subscribe(cInfo.Topic) 40 d.Chk.NoError(err) 41 42 listenForAndHandleMessage := func() { 43 msg, err := sub.Next(context.Background()) 44 d.PanicIfError(err) 45 sender := base58.Encode(msg.From) 46 msgMap := map[string]string{} 47 err = json.Unmarshal(msg.Data, &msgMap) 48 if err != nil { 49 dbg.Debug("ReceiveMessages: received non-json msg: %s from: %s, error: %s", msg.Data, sender, err) 50 return 51 } 52 msgData := msgMap["data"] 53 h, err := cInfo.Delegate.HashFromMsgData(msgData) 54 if err != nil { 55 dbg.Debug("ReceiveMessages: received unknown msg: %s from: %s", msgData, sender) 56 return 57 } 58 59 defer lockSeenF()() 60 if !seenHash[h] { 61 events <- ChatEvent{EventType: SyncEvent, Event: msgData} 62 seenHash[h] = true 63 dbg.Debug("got msgData: %s from: %s(%s)", msgData, sender, msgMap["user"]) 64 } 65 } 66 67 dbg.Debug("start listening for msgs on channel: %s", cInfo.Topic) 68 for { 69 listenForAndHandleMessage() 70 } 71 panic("unreachable") 72 } 73 74 // Publish asks the delegate to format a hash/ClientInfo into a suitable msg 75 // and publishes that using IPFS pubsub. 76 func Publish(node *core.IpfsNode, cInfo ClientInfo, h hash.Hash) { 77 defer func() { 78 if r := recover(); r != nil { 79 dbg.Debug("Publish failed, error: %s", r) 80 } 81 }() 82 msgData := cInfo.Delegate.GenMessageData(cInfo, h) 83 m, err := json.Marshal(map[string]string{"user": cInfo.Username, "data": msgData}) 84 if err != nil { 85 86 } 87 d.PanicIfError(err) 88 dbg.Debug("publishing to topic: %s, msg: %s", cInfo.Topic, m) 89 node.Floodsub.Publish(cInfo.Topic, append(m, []byte("\r\n")...)) 90 91 defer lockSeenF()() 92 seenHash[h] = true 93 }