diff --git a/db/item/db/main.go b/db/item/db/main.go index 7b3b38b2..c694acd0 100644 --- a/db/item/db/main.go +++ b/db/item/db/main.go @@ -41,6 +41,14 @@ const ( TopicMemoRoomPost = "memo_room_post" TopicMemoSeenPost = "memo_seen_post" + TopicMemoAddrLinkRequest = "memo_addr_link_request" + TopicMemoAddrLinkRequested = "memo_addr_link_requested" + TopicMemoLinkAccept = "memo_link_accept" + TopicMemoLinkAccepted = "memo_link_accepted" + TopicMemoLinkRequest = "memo_link_request" + TopicMemoLinkRevoke = "memo_link_revoke" + TopicMemoLinkRevoked = "memo_link_revoked" + TopicChainBlock = "chain_block" TopicChainBlockHeight = "chain_block_height" TopicChainHeightBlock = "chain_height_block" diff --git a/db/item/memo/addr_link_request.go b/db/item/memo/addr_link_request.go new file mode 100644 index 00000000..6513395f --- /dev/null +++ b/db/item/memo/addr_link_request.go @@ -0,0 +1,77 @@ +package memo + +import ( + "context" + "fmt" + "github.com/jchavannes/jgo/jutil" + "github.com/memocash/index/db/client" + "github.com/memocash/index/db/item/db" + "github.com/memocash/index/ref/bitcoin/memo" + "github.com/memocash/index/ref/config" + "time" +) + +type AddrLinkRequest struct { + Addr [25]byte + Seen time.Time + TxHash [32]byte +} + +func (r *AddrLinkRequest) GetTopic() string { + return db.TopicMemoAddrLinkRequest +} + +func (r *AddrLinkRequest) GetShardSource() uint { + return client.GenShardSource(r.Addr[:]) +} + +func (r *AddrLinkRequest) GetUid() []byte { + return jutil.CombineBytes( + r.Addr[:], + jutil.GetTimeByteNanoBig(r.Seen), + jutil.ByteReverse(r.TxHash[:]), + ) +} + +func (r *AddrLinkRequest) SetUid(uid []byte) { + if len(uid) != memo.AddressLength+memo.Int8Size+memo.TxHashLength { + return + } + copy(r.Addr[:], uid[:25]) + r.Seen = jutil.GetByteTimeNanoBig(uid[25:33]) + copy(r.TxHash[:], jutil.ByteReverse(uid[33:65])) +} + +func (r *AddrLinkRequest) Serialize() []byte { + return nil +} + +func (r *AddrLinkRequest) Deserialize([]byte) {} + +func GetAddrLinkRequests(ctx context.Context, addrs [][25]byte) ([]*AddrLinkRequest, error) { + var shardPrefixes = make(map[uint32][][]byte) + for i := range addrs { + shard := client.GenShardSource32(addrs[i][:]) + shardPrefixes[shard] = append(shardPrefixes[shard], addrs[i][:]) + } + shardConfigs := config.GetQueueShards() + var addrLinkRequests []*AddrLinkRequest + for shard, prefixes := range shardPrefixes { + shardConfig := config.GetShardConfig(shard, shardConfigs) + dbClient := client.NewClient(shardConfig.GetHost()) + if err := dbClient.GetWOpts(client.Opts{ + Topic: db.TopicMemoAddrLinkRequest, + Prefixes: prefixes, + Max: client.ExLargeLimit, + Context: ctx, + }); err != nil { + return nil, fmt.Errorf("error getting db addr memo link requests by prefix; %w", err) + } + for _, msg := range dbClient.Messages { + var addrLinkRequest = new(AddrLinkRequest) + db.Set(addrLinkRequest, msg) + addrLinkRequests = append(addrLinkRequests, addrLinkRequest) + } + } + return addrLinkRequests, nil +} diff --git a/db/item/memo/addr_link_requested.go b/db/item/memo/addr_link_requested.go new file mode 100644 index 00000000..46e97911 --- /dev/null +++ b/db/item/memo/addr_link_requested.go @@ -0,0 +1,77 @@ +package memo + +import ( + "context" + "fmt" + "github.com/jchavannes/jgo/jutil" + "github.com/memocash/index/db/client" + "github.com/memocash/index/db/item/db" + "github.com/memocash/index/ref/bitcoin/memo" + "github.com/memocash/index/ref/config" + "time" +) + +type AddrLinkRequested struct { + Addr [25]byte + Seen time.Time + TxHash [32]byte +} + +func (r *AddrLinkRequested) GetTopic() string { + return db.TopicMemoAddrLinkRequested +} + +func (r *AddrLinkRequested) GetShardSource() uint { + return client.GenShardSource(r.Addr[:]) +} + +func (r *AddrLinkRequested) GetUid() []byte { + return jutil.CombineBytes( + r.Addr[:], + jutil.GetTimeByteNanoBig(r.Seen), + jutil.ByteReverse(r.TxHash[:]), + ) +} + +func (r *AddrLinkRequested) SetUid(uid []byte) { + if len(uid) != memo.AddressLength+memo.Int8Size+memo.TxHashLength { + return + } + copy(r.Addr[:], uid[:25]) + r.Seen = jutil.GetByteTimeNanoBig(uid[25:33]) + copy(r.TxHash[:], jutil.ByteReverse(uid[33:65])) +} + +func (r *AddrLinkRequested) Serialize() []byte { + return nil +} + +func (r *AddrLinkRequested) Deserialize([]byte) {} + +func GetAddrLinkRequesteds(ctx context.Context, addrs [][25]byte) ([]*AddrLinkRequested, error) { + var shardPrefixes = make(map[uint32][][]byte) + for i := range addrs { + shard := client.GenShardSource32(addrs[i][:]) + shardPrefixes[shard] = append(shardPrefixes[shard], addrs[i][:]) + } + shardConfigs := config.GetQueueShards() + var addrLinkRequesteds []*AddrLinkRequested + for shard, prefixes := range shardPrefixes { + shardConfig := config.GetShardConfig(shard, shardConfigs) + dbClient := client.NewClient(shardConfig.GetHost()) + if err := dbClient.GetWOpts(client.Opts{ + Topic: db.TopicMemoAddrLinkRequested, + Prefixes: prefixes, + Max: client.ExLargeLimit, + Context: ctx, + }); err != nil { + return nil, fmt.Errorf("error getting db addr memo link requesteds by prefix; %w", err) + } + for _, msg := range dbClient.Messages { + var addrLinkRequested = new(AddrLinkRequested) + db.Set(addrLinkRequested, msg) + addrLinkRequesteds = append(addrLinkRequesteds, addrLinkRequested) + } + } + return addrLinkRequesteds, nil +} diff --git a/db/item/memo/link_accept.go b/db/item/memo/link_accept.go new file mode 100644 index 00000000..b3ee4939 --- /dev/null +++ b/db/item/memo/link_accept.go @@ -0,0 +1,51 @@ +package memo + +import ( + "github.com/jchavannes/jgo/jutil" + "github.com/memocash/index/db/client" + "github.com/memocash/index/db/item/db" + "github.com/memocash/index/ref/bitcoin/memo" +) + +type LinkAccept struct { + TxHash [32]byte + Addr [25]byte + RequestTxHash [32]byte + Message string +} + +func (r *LinkAccept) GetTopic() string { + return db.TopicMemoLinkAccept +} + +func (r *LinkAccept) GetShardSource() uint { + return client.GenShardSource(r.TxHash[:]) +} + +func (r *LinkAccept) GetUid() []byte { + return jutil.ByteReverse(r.TxHash[:]) +} + +func (r *LinkAccept) SetUid(uid []byte) { + if len(uid) != memo.TxHashLength { + panic("invalid uid size for link accept") + } + copy(r.TxHash[:], jutil.ByteReverse(uid)) +} + +func (r *LinkAccept) Serialize() []byte { + return jutil.CombineBytes( + r.Addr[:], + jutil.ByteReverse(r.RequestTxHash[:]), + []byte(r.Message), + ) +} + +func (r *LinkAccept) Deserialize(data []byte) { + if len(data) < memo.AddressLength+memo.TxHashLength { + panic("invalid data size for link accept") + } + copy(r.Addr[:], data[:25]) + copy(r.RequestTxHash[:], jutil.ByteReverse(data[25:57])) + r.Message = string(data[57:]) +} diff --git a/db/item/memo/link_accepted.go b/db/item/memo/link_accepted.go new file mode 100644 index 00000000..3e04e1dc --- /dev/null +++ b/db/item/memo/link_accepted.go @@ -0,0 +1,43 @@ +package memo + +import ( + "github.com/jchavannes/jgo/jutil" + "github.com/memocash/index/db/client" + "github.com/memocash/index/db/item/db" + "github.com/memocash/index/ref/bitcoin/memo" +) + +type LinkAccepted struct { + RequestTxHash [32]byte + TxHash [32]byte +} + +func (r *LinkAccepted) GetTopic() string { + return db.TopicMemoLinkAccepted +} + +func (r *LinkAccepted) GetShardSource() uint { + return client.GenShardSource(r.RequestTxHash[:]) +} + +func (r *LinkAccepted) GetUid() []byte { + return jutil.ByteReverse(r.RequestTxHash[:]) +} + +func (r *LinkAccepted) SetUid(uid []byte) { + if len(uid) != memo.TxHashLength { + panic("invalid uid size for link accepted") + } + copy(r.RequestTxHash[:], jutil.ByteReverse(uid)) +} + +func (r *LinkAccepted) Serialize() []byte { + return jutil.ByteReverse(r.TxHash[:]) +} + +func (r *LinkAccepted) Deserialize(data []byte) { + if len(data) != memo.TxHashLength { + panic("invalid data size for link accepted") + } + copy(r.TxHash[:], jutil.ByteReverse(data)) +} diff --git a/db/item/memo/link_request.go b/db/item/memo/link_request.go new file mode 100644 index 00000000..1d0d3504 --- /dev/null +++ b/db/item/memo/link_request.go @@ -0,0 +1,80 @@ +package memo + +import ( + "context" + "fmt" + "github.com/jchavannes/jgo/jutil" + "github.com/memocash/index/db/client" + "github.com/memocash/index/db/item/db" + "github.com/memocash/index/ref/bitcoin/memo" + "github.com/memocash/index/ref/config" +) + +type LinkRequest struct { + TxHash [32]byte + ChildAddr [25]byte + ParentAddr [25]byte + Message string +} + +func (r *LinkRequest) GetTopic() string { + return db.TopicMemoLinkRequest +} + +func (r *LinkRequest) GetShardSource() uint { + return client.GenShardSource(r.TxHash[:]) +} + +func (r *LinkRequest) GetUid() []byte { + return jutil.ByteReverse(r.TxHash[:]) +} + +func (r *LinkRequest) SetUid(uid []byte) { + if len(uid) != memo.TxHashLength { + panic("invalid uid size for link request") + } + copy(r.TxHash[:], jutil.ByteReverse(uid)) +} + +func (r *LinkRequest) Serialize() []byte { + return jutil.CombineBytes( + r.ChildAddr[:], + r.ParentAddr[:], + []byte(r.Message), + ) +} + +func (r *LinkRequest) Deserialize(data []byte) { + if len(data) < memo.AddressLength*2 { + panic("invalid data size for link request") + } + copy(r.ChildAddr[:], data[:25]) + copy(r.ParentAddr[:], data[25:50]) + r.Message = string(data[50:]) +} + +func GetLinkRequests(ctx context.Context, txHashes [][32]byte) ([]*LinkRequest, error) { + var shardUids = make(map[uint32][][]byte) + for i := range txHashes { + shard := db.GetShardIdFromByte32(txHashes[i][:]) + shardUids[shard] = append(shardUids[shard], jutil.ByteReverse(txHashes[i][:])) + } + var linkRequests []*LinkRequest + for shard, uids := range shardUids { + shardConfig := config.GetShardConfig(shard, config.GetQueueShards()) + dbClient := client.NewClient(shardConfig.GetHost()) + if err := dbClient.GetWOpts(client.Opts{ + Context: ctx, + Topic: db.TopicMemoLinkRequest, + Uids: uids, + }); err != nil { + return nil, fmt.Errorf("error getting client message memo link requests; %w", err) + } + for _, msg := range dbClient.Messages { + var linkRequest = new(LinkRequest) + db.Set(linkRequest, msg) + linkRequests = append(linkRequests, linkRequest) + } + } + return linkRequests, nil +} diff --git a/db/item/memo/link_revoke.go b/db/item/memo/link_revoke.go new file mode 100644 index 00000000..5d716ce3 --- /dev/null +++ b/db/item/memo/link_revoke.go @@ -0,0 +1,51 @@ +package memo + +import ( + "github.com/jchavannes/jgo/jutil" + "github.com/memocash/index/db/client" + "github.com/memocash/index/db/item/db" + "github.com/memocash/index/ref/bitcoin/memo" +) + +type LinkRevoke struct { + TxHash [32]byte + Addr [25]byte + AcceptTxHash [32]byte + Message string +} + +func (r *LinkRevoke) GetTopic() string { + return db.TopicMemoLinkRevoke +} + +func (r *LinkRevoke) GetShardSource() uint { + return client.GenShardSource(r.TxHash[:]) +} + +func (r *LinkRevoke) GetUid() []byte { + return jutil.ByteReverse(r.TxHash[:]) +} + +func (r *LinkRevoke) SetUid(uid []byte) { + if len(uid) != memo.TxHashLength { + panic("invalid uid size for link revoke") + } + copy(r.TxHash[:], jutil.ByteReverse(uid)) +} + +func (r *LinkRevoke) Serialize() []byte { + return jutil.CombineBytes( + r.Addr[:], + jutil.ByteReverse(r.AcceptTxHash[:]), + []byte(r.Message), + ) +} + +func (r *LinkRevoke) Deserialize(data []byte) { + if len(data) < memo.AddressLength+memo.TxHashLength { + panic("invalid data size for link revoke") + } + copy(r.Addr[:], data[:25]) + copy(r.AcceptTxHash[:], jutil.ByteReverse(data[25:57])) + r.Message = string(data[57:]) +} diff --git a/db/item/memo/link_revoked.go b/db/item/memo/link_revoked.go new file mode 100644 index 00000000..3030215a --- /dev/null +++ b/db/item/memo/link_revoked.go @@ -0,0 +1,43 @@ +package memo + +import ( + "github.com/jchavannes/jgo/jutil" + "github.com/memocash/index/db/client" + "github.com/memocash/index/db/item/db" + "github.com/memocash/index/ref/bitcoin/memo" +) + +type LinkRevoked struct { + AcceptTxHash [32]byte + TxHash [32]byte +} + +func (r *LinkRevoked) GetTopic() string { + return db.TopicMemoLinkRevoked +} + +func (r *LinkRevoked) GetShardSource() uint { + return client.GenShardSource(r.AcceptTxHash[:]) +} + +func (r *LinkRevoked) GetUid() []byte { + return jutil.ByteReverse(r.AcceptTxHash[:]) +} + +func (r *LinkRevoked) SetUid(uid []byte) { + if len(uid) != memo.TxHashLength { + panic("invalid uid size for link revoked") + } + copy(r.AcceptTxHash[:], jutil.ByteReverse(uid)) +} + +func (r *LinkRevoked) Serialize() []byte { + return jutil.ByteReverse(r.TxHash[:]) +} + +func (r *LinkRevoked) Deserialize(data []byte) { + if len(data) != memo.TxHashLength { + panic("invalid data size for link revoked") + } + copy(r.TxHash[:], jutil.ByteReverse(data)) +} diff --git a/db/item/memo/main.go b/db/item/memo/main.go index d1463b90..80b6d09c 100644 --- a/db/item/memo/main.go +++ b/db/item/memo/main.go @@ -20,5 +20,12 @@ func GetTopics() []db.Object { &PostRoom{}, &RoomFollow{}, &RoomPost{}, + &LinkRequest{}, + &AddrLinkRequest{}, + &AddrLinkRequested{}, + &LinkAccept{}, + &LinkAccepted{}, + &LinkRevoke{}, + &LinkRevoked{}, } } diff --git a/graph/attach/memo_profile.go b/graph/attach/memo_profile.go index b405e35f..5fbafcc4 100644 --- a/graph/attach/memo_profile.go +++ b/graph/attach/memo_profile.go @@ -292,3 +292,108 @@ func (a *MemoProfile) AttachPics() { } } } + +func (a *MemoProfile) AttachLinks() { + defer a.Wait.Done() + if !a.HasField([]string{"links"}) { + return + } + var allAddresses [][25]byte + var allLinkRequests []*memo.LinkRequest + var checkAddresses = a.getAddresses() + for len(checkAddresses) > 0 { + addrLinkRequests, err := memo.GetAddrLinkRequests(a.Ctx, checkAddresses) + if err != nil { + a.AddError(fmt.Errorf("error getting addr link requests for profile attach; %w", err)) + return + } + addrLinkRequesteds, err := memo.GetAddrLinkRequesteds(a.Ctx, checkAddresses) + if err != nil { + a.AddError(fmt.Errorf("error getting addr link requesteds for profile attach; %w", err)) + return + } + var linkRequestTxHashes [][32]byte + for _, addrLinkRequest := range addrLinkRequests { + linkRequestTxHashes = append(linkRequestTxHashes, addrLinkRequest.TxHash) + } + for _, addrLinkRequested := range addrLinkRequesteds { + linkRequestTxHashes = append(linkRequestTxHashes, addrLinkRequested.TxHash) + } + linkRequests, err := memo.GetLinkRequests(a.Ctx, linkRequestTxHashes) + if err != nil { + a.AddError(fmt.Errorf("error getting link requests for profile attach; %w", err)) + return + } + for _, linkRequest := range linkRequests { + var found bool + for _, allLinkRequest := range allLinkRequests { + if linkRequest.TxHash == allLinkRequest.TxHash { + found = true + break + } + } + if !found { + allLinkRequests = append(allLinkRequests, linkRequest) + } + } + allAddresses = checkAddresses + checkAddresses = nil + for _, linkRequest := range linkRequests { + var childAddrFound, parentAddrFound bool + for _, addr := range allAddresses { + if linkRequest.ChildAddr == addr { + childAddrFound = true + } else if linkRequest.ParentAddr == addr { + parentAddrFound = true + } + } + if !childAddrFound { + checkAddresses = append(checkAddresses, linkRequest.ChildAddr) + } else if !parentAddrFound { + checkAddresses = append(checkAddresses, linkRequest.ParentAddr) + } + } + } + a.Mutex.Lock() + defer a.Mutex.Unlock() + for _, profile := range a.Profiles { + var foundLinkRequests []*memo.LinkRequest + for _, linkRequest := range allLinkRequests { + if linkRequest.ChildAddr == profile.Address || linkRequest.ParentAddr == profile.Address { + foundLinkRequests = append(foundLinkRequests, linkRequest) + } + } + for more := true; more; { + more = false + for _, linkRequest := range allLinkRequests { + var shouldBeIncluded, alreadyIncluded bool + for _, foundLinkRequest := range foundLinkRequests { + if foundLinkRequest.TxHash == linkRequest.TxHash { + alreadyIncluded = true + break + } + if linkRequest.ChildAddr == foundLinkRequest.ParentAddr || + linkRequest.ParentAddr == foundLinkRequest.ChildAddr { + shouldBeIncluded = true + } + } + if alreadyIncluded { + continue + } else if shouldBeIncluded { + foundLinkRequests = append(foundLinkRequests, linkRequest) + more = true + } + } + } + for _, linkRequest := range foundLinkRequests { + profile.Links = append(profile.Links, &model.Link{ + Request: &model.LinkRequest{ + Child: &model.Lock{Address: linkRequest.ChildAddr}, + Parent: &model.Lock{Address: linkRequest.ParentAddr}, + Message: linkRequest.Message, + Tx: &model.Tx{Hash: linkRequest.TxHash}, + }, + }) + } + } +} diff --git a/graph/generated/generated.go b/graph/generated/generated.go index 09d71ffb..375987bc 100644 --- a/graph/generated/generated.go +++ b/graph/generated/generated.go @@ -76,6 +76,29 @@ type ComplexityRoot struct { TxHash func(childComplexity int) int } + Link struct { + Accept func(childComplexity int) int + Request func(childComplexity int) int + Revoke func(childComplexity int) int + } + + LinkAccept struct { + Message func(childComplexity int) int + Tx func(childComplexity int) int + } + + LinkRequest struct { + Child func(childComplexity int) int + Message func(childComplexity int) int + Parent func(childComplexity int) int + Tx func(childComplexity int) int + } + + LinkRevoke struct { + Message func(childComplexity int) int + Tx func(childComplexity int) int + } + Lock struct { Address func(childComplexity int) int Profile func(childComplexity int) int @@ -102,6 +125,7 @@ type ComplexityRoot struct { Address func(childComplexity int) int Followers func(childComplexity int, start *model.Date) int Following func(childComplexity int, start *model.Date) int + Links func(childComplexity int) int Lock func(childComplexity int) int Name func(childComplexity int) int Pic func(childComplexity int) int @@ -441,6 +465,83 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Like.TxHash(childComplexity), true + case "Link.accept": + if e.complexity.Link.Accept == nil { + break + } + + return e.complexity.Link.Accept(childComplexity), true + + case "Link.request": + if e.complexity.Link.Request == nil { + break + } + + return e.complexity.Link.Request(childComplexity), true + + case "Link.revoke": + if e.complexity.Link.Revoke == nil { + break + } + + return e.complexity.Link.Revoke(childComplexity), true + + case "LinkAccept.message": + if e.complexity.LinkAccept.Message == nil { + break + } + + return e.complexity.LinkAccept.Message(childComplexity), true + + case "LinkAccept.tx": + if e.complexity.LinkAccept.Tx == nil { + break + } + + return e.complexity.LinkAccept.Tx(childComplexity), true + + case "LinkRequest.child": + if e.complexity.LinkRequest.Child == nil { + break + } + + return e.complexity.LinkRequest.Child(childComplexity), true + + case "LinkRequest.message": + if e.complexity.LinkRequest.Message == nil { + break + } + + return e.complexity.LinkRequest.Message(childComplexity), true + + case "LinkRequest.parent": + if e.complexity.LinkRequest.Parent == nil { + break + } + + return e.complexity.LinkRequest.Parent(childComplexity), true + + case "LinkRequest.tx": + if e.complexity.LinkRequest.Tx == nil { + break + } + + return e.complexity.LinkRequest.Tx(childComplexity), true + + case "LinkRevoke.message": + if e.complexity.LinkRevoke.Message == nil { + break + } + + return e.complexity.LinkRevoke.Message(childComplexity), true + + case "LinkRevoke.tx": + if e.complexity.LinkRevoke.Tx == nil { + break + } + + return e.complexity.LinkRevoke.Tx(childComplexity), true + case "Lock.address": if e.complexity.Lock.Address == nil { break @@ -573,6 +674,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Profile.Following(childComplexity, args["start"].(*model.Date)), true + case "Profile.links": + if e.complexity.Profile.Links == nil { + break + } + + return e.complexity.Profile.Links(childComplexity), true + case "Profile.lock": if e.complexity.Profile.Lock == nil { break @@ -1486,6 +1594,7 @@ var sources = []*ast.Source{ `, BuiltIn: false}, {Name: "../schema/profile.graphqls", Input: `type Profile { lock: Lock! + links: [Link] address: Address! name: SetName profile: SetProfile @@ -1552,6 +1661,29 @@ type Like { post: Post tip: Int64 } + +type Link { + request: LinkRequest! + accept: LinkAccept + revoke: LinkRevoke +} + +type LinkRequest { + child: Lock! + parent: Lock! + message: String! + tx: Tx! +} + +type LinkAccept { + message: String! + tx: Tx! +} + +type LinkRevoke { + message: String! + tx: Tx! +} `, BuiltIn: false}, {Name: "../schema/query.graphqls", Input: `type Query { tx(hash: Hash!): Tx @@ -3140,8 +3272,557 @@ func (ec *executionContext) fieldContext_Like_post(ctx context.Context, field gr return fc, nil } -func (ec *executionContext) _Like_tip(ctx context.Context, field graphql.CollectedField, obj *model.Like) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Like_tip(ctx, field) +func (ec *executionContext) _Like_tip(ctx context.Context, field graphql.CollectedField, obj *model.Like) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Like_tip(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Tip, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalOInt642int64(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Like_tip(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Like", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int64 does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Link_request(ctx context.Context, field graphql.CollectedField, obj *model.Link) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Link_request(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Request, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.LinkRequest) + fc.Result = res + return ec.marshalNLinkRequest2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLinkRequest(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Link_request(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Link", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "child": + return ec.fieldContext_LinkRequest_child(ctx, field) + case "parent": + return ec.fieldContext_LinkRequest_parent(ctx, field) + case "message": + return ec.fieldContext_LinkRequest_message(ctx, field) + case "tx": + return ec.fieldContext_LinkRequest_tx(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type LinkRequest", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Link_accept(ctx context.Context, field graphql.CollectedField, obj *model.Link) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Link_accept(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Accept, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*model.LinkAccept) + fc.Result = res + return ec.marshalOLinkAccept2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLinkAccept(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Link_accept(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Link", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "message": + return ec.fieldContext_LinkAccept_message(ctx, field) + case "tx": + return ec.fieldContext_LinkAccept_tx(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type LinkAccept", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Link_revoke(ctx context.Context, field graphql.CollectedField, obj *model.Link) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Link_revoke(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Revoke, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*model.LinkRevoke) + fc.Result = res + return ec.marshalOLinkRevoke2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLinkRevoke(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Link_revoke(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Link", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "message": + return ec.fieldContext_LinkRevoke_message(ctx, field) + case "tx": + return ec.fieldContext_LinkRevoke_tx(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type LinkRevoke", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _LinkAccept_message(ctx context.Context, field graphql.CollectedField, obj *model.LinkAccept) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_LinkAccept_message(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Message, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_LinkAccept_message(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "LinkAccept", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _LinkAccept_tx(ctx context.Context, field graphql.CollectedField, obj *model.LinkAccept) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_LinkAccept_tx(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Tx, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Tx) + fc.Result = res + return ec.marshalNTx2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐTx(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_LinkAccept_tx(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "LinkAccept", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "hash": + return ec.fieldContext_Tx_hash(ctx, field) + case "raw": + return ec.fieldContext_Tx_raw(ctx, field) + case "inputs": + return ec.fieldContext_Tx_inputs(ctx, field) + case "outputs": + return ec.fieldContext_Tx_outputs(ctx, field) + case "blocks": + return ec.fieldContext_Tx_blocks(ctx, field) + case "seen": + return ec.fieldContext_Tx_seen(ctx, field) + case "version": + return ec.fieldContext_Tx_version(ctx, field) + case "locktime": + return ec.fieldContext_Tx_locktime(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Tx", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _LinkRequest_child(ctx context.Context, field graphql.CollectedField, obj *model.LinkRequest) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_LinkRequest_child(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Child, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Lock) + fc.Result = res + return ec.marshalNLock2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLock(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_LinkRequest_child(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "LinkRequest", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "address": + return ec.fieldContext_Lock_address(ctx, field) + case "profile": + return ec.fieldContext_Lock_profile(ctx, field) + case "txs": + return ec.fieldContext_Lock_txs(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Lock", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _LinkRequest_parent(ctx context.Context, field graphql.CollectedField, obj *model.LinkRequest) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_LinkRequest_parent(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Parent, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Lock) + fc.Result = res + return ec.marshalNLock2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLock(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_LinkRequest_parent(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "LinkRequest", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "address": + return ec.fieldContext_Lock_address(ctx, field) + case "profile": + return ec.fieldContext_Lock_profile(ctx, field) + case "txs": + return ec.fieldContext_Lock_txs(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Lock", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _LinkRequest_message(ctx context.Context, field graphql.CollectedField, obj *model.LinkRequest) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_LinkRequest_message(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Message, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_LinkRequest_message(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "LinkRequest", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _LinkRequest_tx(ctx context.Context, field graphql.CollectedField, obj *model.LinkRequest) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_LinkRequest_tx(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Tx, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Tx) + fc.Result = res + return ec.marshalNTx2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐTx(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_LinkRequest_tx(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "LinkRequest", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "hash": + return ec.fieldContext_Tx_hash(ctx, field) + case "raw": + return ec.fieldContext_Tx_raw(ctx, field) + case "inputs": + return ec.fieldContext_Tx_inputs(ctx, field) + case "outputs": + return ec.fieldContext_Tx_outputs(ctx, field) + case "blocks": + return ec.fieldContext_Tx_blocks(ctx, field) + case "seen": + return ec.fieldContext_Tx_seen(ctx, field) + case "version": + return ec.fieldContext_Tx_version(ctx, field) + case "locktime": + return ec.fieldContext_Tx_locktime(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Tx", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _LinkRevoke_message(ctx context.Context, field graphql.CollectedField, obj *model.LinkRevoke) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_LinkRevoke_message(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Message, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_LinkRevoke_message(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "LinkRevoke", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _LinkRevoke_tx(ctx context.Context, field graphql.CollectedField, obj *model.LinkRevoke) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_LinkRevoke_tx(ctx, field) if err != nil { return graphql.Null } @@ -3154,28 +3835,49 @@ func (ec *executionContext) _Like_tip(ctx context.Context, field graphql.Collect }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Tip, nil + return obj.Tx, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(int64) + res := resTmp.(*model.Tx) fc.Result = res - return ec.marshalOInt642int64(ctx, field.Selections, res) + return ec.marshalNTx2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐTx(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Like_tip(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_LinkRevoke_tx(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Like", + Object: "LinkRevoke", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int64 does not have child fields") + switch field.Name { + case "hash": + return ec.fieldContext_Tx_hash(ctx, field) + case "raw": + return ec.fieldContext_Tx_raw(ctx, field) + case "inputs": + return ec.fieldContext_Tx_inputs(ctx, field) + case "outputs": + return ec.fieldContext_Tx_outputs(ctx, field) + case "blocks": + return ec.fieldContext_Tx_blocks(ctx, field) + case "seen": + return ec.fieldContext_Tx_seen(ctx, field) + case "version": + return ec.fieldContext_Tx_version(ctx, field) + case "locktime": + return ec.fieldContext_Tx_locktime(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Tx", field.Name) }, } return fc, nil @@ -3260,6 +3962,8 @@ func (ec *executionContext) fieldContext_Lock_profile(ctx context.Context, field switch field.Name { case "lock": return ec.fieldContext_Profile_lock(ctx, field) + case "links": + return ec.fieldContext_Profile_links(ctx, field) case "address": return ec.fieldContext_Profile_address(ctx, field) case "name": @@ -3934,6 +4638,55 @@ func (ec *executionContext) fieldContext_Profile_lock(ctx context.Context, field return fc, nil } +func (ec *executionContext) _Profile_links(ctx context.Context, field graphql.CollectedField, obj *model.Profile) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Profile_links(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Links, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.Link) + fc.Result = res + return ec.marshalOLink2ᚕᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLink(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Profile_links(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Profile", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "request": + return ec.fieldContext_Link_request(ctx, field) + case "accept": + return ec.fieldContext_Link_accept(ctx, field) + case "revoke": + return ec.fieldContext_Link_revoke(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Link", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Profile_address(ctx context.Context, field graphql.CollectedField, obj *model.Profile) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Profile_address(ctx, field) if err != nil { @@ -4904,6 +5657,8 @@ func (ec *executionContext) fieldContext_Query_profiles(ctx context.Context, fie switch field.Name { case "lock": return ec.fieldContext_Profile_lock(ctx, field) + case "links": + return ec.fieldContext_Profile_links(ctx, field) case "address": return ec.fieldContext_Profile_address(ctx, field) case "name": @@ -8009,6 +8764,8 @@ func (ec *executionContext) fieldContext_Subscription_profiles(ctx context.Conte switch field.Name { case "lock": return ec.fieldContext_Profile_lock(ctx, field) + case "links": + return ec.fieldContext_Profile_links(ctx, field) case "address": return ec.fieldContext_Profile_address(ctx, field) case "name": @@ -11675,6 +12432,161 @@ func (ec *executionContext) _Like(ctx context.Context, sel ast.SelectionSet, obj return out } +var linkImplementors = []string{"Link"} + +func (ec *executionContext) _Link(ctx context.Context, sel ast.SelectionSet, obj *model.Link) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, linkImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Link") + case "request": + + out.Values[i] = ec._Link_request(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "accept": + + out.Values[i] = ec._Link_accept(ctx, field, obj) + + case "revoke": + + out.Values[i] = ec._Link_revoke(ctx, field, obj) + + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var linkAcceptImplementors = []string{"LinkAccept"} + +func (ec *executionContext) _LinkAccept(ctx context.Context, sel ast.SelectionSet, obj *model.LinkAccept) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, linkAcceptImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("LinkAccept") + case "message": + + out.Values[i] = ec._LinkAccept_message(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "tx": + + out.Values[i] = ec._LinkAccept_tx(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var linkRequestImplementors = []string{"LinkRequest"} + +func (ec *executionContext) _LinkRequest(ctx context.Context, sel ast.SelectionSet, obj *model.LinkRequest) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, linkRequestImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("LinkRequest") + case "child": + + out.Values[i] = ec._LinkRequest_child(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "parent": + + out.Values[i] = ec._LinkRequest_parent(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "message": + + out.Values[i] = ec._LinkRequest_message(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "tx": + + out.Values[i] = ec._LinkRequest_tx(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var linkRevokeImplementors = []string{"LinkRevoke"} + +func (ec *executionContext) _LinkRevoke(ctx context.Context, sel ast.SelectionSet, obj *model.LinkRevoke) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, linkRevokeImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("LinkRevoke") + case "message": + + out.Values[i] = ec._LinkRevoke_message(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "tx": + + out.Values[i] = ec._LinkRevoke_tx(ctx, field, obj) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var lockImplementors = []string{"Lock"} func (ec *executionContext) _Lock(ctx context.Context, sel ast.SelectionSet, obj *model.Lock) graphql.Marshaler { @@ -11836,6 +12748,10 @@ func (ec *executionContext) _Profile(ctx context.Context, sel ast.SelectionSet, if out.Values[i] == graphql.Null { invalids++ } + case "links": + + out.Values[i] = ec._Profile_links(ctx, field, obj) + case "address": out.Values[i] = ec._Profile_address(ctx, field, obj) @@ -13386,6 +14302,16 @@ func (ec *executionContext) marshalNLike2ᚖgithubᚗcomᚋmemocashᚋindexᚋgr return ec._Like(ctx, sel, v) } +func (ec *executionContext) marshalNLinkRequest2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLinkRequest(ctx context.Context, sel ast.SelectionSet, v *model.LinkRequest) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._LinkRequest(ctx, sel, v) +} + func (ec *executionContext) marshalNLock2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLock(ctx context.Context, sel ast.SelectionSet, v *model.Lock) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -14230,6 +15156,68 @@ func (ec *executionContext) marshalOLike2ᚕᚖgithubᚗcomᚋmemocashᚋindex return ret } +func (ec *executionContext) marshalOLink2ᚕᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLink(ctx context.Context, sel ast.SelectionSet, v []*model.Link) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalOLink2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLink(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + return ret +} + +func (ec *executionContext) marshalOLink2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLink(ctx context.Context, sel ast.SelectionSet, v *model.Link) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._Link(ctx, sel, v) +} + +func (ec *executionContext) marshalOLinkAccept2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLinkAccept(ctx context.Context, sel ast.SelectionSet, v *model.LinkAccept) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._LinkAccept(ctx, sel, v) +} + +func (ec *executionContext) marshalOLinkRevoke2ᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLinkRevoke(ctx context.Context, sel ast.SelectionSet, v *model.LinkRevoke) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._LinkRevoke(ctx, sel, v) +} + func (ec *executionContext) marshalOLock2ᚕᚖgithubᚗcomᚋmemocashᚋindexᚋgraphᚋmodelᚐLock(ctx context.Context, sel ast.SelectionSet, v []*model.Lock) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/graph/model/models.go b/graph/model/models.go index 45df655e..6deffaf8 100644 --- a/graph/model/models.go +++ b/graph/model/models.go @@ -60,6 +60,7 @@ type Block struct { type Profile struct { Address Address `json:"address"` + Links []*Link `json:"links"` Name *SetName `json:"name"` Profile *SetProfile `json:"profile"` Pic *SetPic `json:"pic"` @@ -70,6 +71,29 @@ type Profile struct { Rooms []*RoomFollow `json:"rooms"` } +type Link struct { + Request *LinkRequest `json:"request"` + Accept *LinkAccept `json:"accept"` + Revoke *LinkRevoke `json:"revoke"` +} + +type LinkRequest struct { + Child *Lock `json:"child"` + Parent *Lock `json:"parent"` + Message string `json:"message"` + Tx *Tx `json:"tx"` +} + +type LinkRevoke struct { + Message string `json:"message"` + Tx *Tx `json:"tx"` +} + +type LinkAccept struct { + Message string `json:"message"` + Tx *Tx `json:"tx"` +} + type Follow struct { TxHash Hash `json:"tx_hash"` Address Address `json:"address"` diff --git a/graph/schema/profile.graphqls b/graph/schema/profile.graphqls index 8851c73f..24201b7d 100644 --- a/graph/schema/profile.graphqls +++ b/graph/schema/profile.graphqls @@ -1,5 +1,6 @@ type Profile { lock: Lock! + links: [Link] address: Address! name: SetName profile: SetProfile @@ -66,3 +67,26 @@ type Like { post: Post tip: Int64 } + +type Link { + request: LinkRequest! + accept: LinkAccept + revoke: LinkRevoke +} + +type LinkRequest { + child: Lock! + parent: Lock! + message: String! + tx: Tx! +} + +type LinkAccept { + message: String! + tx: Tx! +} + +type LinkRevoke { + message: String! + tx: Tx! +} diff --git a/node/obj/op_return/main.go b/node/obj/op_return/main.go index 1a5310cd..81bbbc6b 100644 --- a/node/obj/op_return/main.go +++ b/node/obj/op_return/main.go @@ -42,6 +42,9 @@ func GetHandlers() ([]*Handler, error) { memoRoomPostHandler, memoRoomFollowHandler, memoRoomUnfollowHandler, + memoLinkRequestHandler, + memoLinkAcceptHandler, + memoLinkRevokeHandler, slpTokenHandler, } for _, opReturn := range handlers { diff --git a/node/obj/op_return/memo_link_accept.go b/node/obj/op_return/memo_link_accept.go new file mode 100644 index 00000000..53c78bba --- /dev/null +++ b/node/obj/op_return/memo_link_accept.go @@ -0,0 +1,57 @@ +package op_return + +import ( + "context" + "fmt" + "github.com/jchavannes/btcd/chaincfg/chainhash" + "github.com/jchavannes/jgo/jutil" + "github.com/memocash/index/db/item" + "github.com/memocash/index/db/item/db" + dbMemo "github.com/memocash/index/db/item/memo" + "github.com/memocash/index/ref/bitcoin/memo" + "github.com/memocash/index/ref/bitcoin/tx/parse" +) + +var memoLinkAcceptHandler = &Handler{ + prefix: memo.PrefixLinkAccept, + handle: func(ctx context.Context, info parse.OpReturn) error { + if len(info.PushData) < 2 { + if err := item.LogProcessError(&item.ProcessError{ + TxHash: info.TxHash, + Error: fmt.Sprintf("invalid set link accept, incorrect push data (%d)", len(info.PushData)), + }); err != nil { + return fmt.Errorf("error saving process error memo link accept incorrect push data; %w", err) + } + return nil + } + if len(info.PushData[1]) != memo.TxHashLength { + if err := item.LogProcessError(&item.ProcessError{ + TxHash: info.TxHash, + Error: fmt.Sprintf("error link accept request tx hash incorrect length: %d", len(info.PushData[1])), + }); err != nil { + return fmt.Errorf("error saving process error memo link accept request tx hash; %w", err) + } + return nil + } + var acceptTxHash chainhash.Hash + copy(acceptTxHash[:], jutil.ByteReverse(info.PushData[1])) + var message string + if len(info.PushData) > 2 { + message = string(info.PushData[2]) + } + var linkAccept = &dbMemo.LinkAccept{ + TxHash: info.TxHash, + Addr: info.Addr, + RequestTxHash: acceptTxHash, + Message: message, + } + var linkAccepted = &dbMemo.LinkAccepted{ + TxHash: info.TxHash, + RequestTxHash: acceptTxHash, + } + if err := db.Save([]db.Object{linkAccept, linkAccepted}); err != nil { + return fmt.Errorf("error saving db lock memo link accept object; %w", err) + } + return nil + }, +} diff --git a/node/obj/op_return/memo_link_request.go b/node/obj/op_return/memo_link_request.go new file mode 100644 index 00000000..79c07e9b --- /dev/null +++ b/node/obj/op_return/memo_link_request.go @@ -0,0 +1,61 @@ +package op_return + +import ( + "context" + "fmt" + "github.com/memocash/index/db/item" + "github.com/memocash/index/db/item/db" + dbMemo "github.com/memocash/index/db/item/memo" + "github.com/memocash/index/ref/bitcoin/memo" + "github.com/memocash/index/ref/bitcoin/tx/parse" + "github.com/memocash/index/ref/bitcoin/wallet" +) + +var memoLinkRequestHandler = &Handler{ + prefix: memo.PrefixLinkRequest, + handle: func(ctx context.Context, info parse.OpReturn) error { + if len(info.PushData) < 2 { + if err := item.LogProcessError(&item.ProcessError{ + TxHash: info.TxHash, + Error: fmt.Sprintf("invalid set link request, incorrect push data (%d)", len(info.PushData)), + }); err != nil { + return fmt.Errorf("error saving process error memo link request incorrect push data; %w", err) + } + return nil + } + if len(info.PushData[1]) != memo.PkHashLength { + if err := item.LogProcessError(&item.ProcessError{ + TxHash: info.TxHash, + Error: fmt.Sprintf("error link request address incorrect length: %d", len(info.PushData[1])), + }); err != nil { + return fmt.Errorf("error saving process error memo link request address; %w", err) + } + return nil + } + parentAddr := wallet.GetAddrFromPkHash(info.PushData[1]) + var message string + if len(info.PushData) > 2 { + message = string(info.PushData[2]) + } + var linkRequest = &dbMemo.LinkRequest{ + TxHash: info.TxHash, + ChildAddr: info.Addr, + ParentAddr: *parentAddr, + Message: message, + } + var addrLinkRequest = &dbMemo.AddrLinkRequest{ + Addr: info.Addr, + Seen: info.Seen, + TxHash: info.TxHash, + } + var addrLinkRequested = &dbMemo.AddrLinkRequested{ + Addr: *parentAddr, + Seen: info.Seen, + TxHash: info.TxHash, + } + if err := db.Save([]db.Object{linkRequest, addrLinkRequest, addrLinkRequested}); err != nil { + return fmt.Errorf("error saving db lock memo link request object; %w", err) + } + return nil + }, +} diff --git a/node/obj/op_return/memo_link_revoke.go b/node/obj/op_return/memo_link_revoke.go new file mode 100644 index 00000000..7906effa --- /dev/null +++ b/node/obj/op_return/memo_link_revoke.go @@ -0,0 +1,57 @@ +package op_return + +import ( + "context" + "fmt" + "github.com/jchavannes/btcd/chaincfg/chainhash" + "github.com/jchavannes/jgo/jutil" + "github.com/memocash/index/db/item" + "github.com/memocash/index/db/item/db" + dbMemo "github.com/memocash/index/db/item/memo" + "github.com/memocash/index/ref/bitcoin/memo" + "github.com/memocash/index/ref/bitcoin/tx/parse" +) + +var memoLinkRevokeHandler = &Handler{ + prefix: memo.PrefixLinkRevoke, + handle: func(ctx context.Context, info parse.OpReturn) error { + if len(info.PushData) < 2 { + if err := item.LogProcessError(&item.ProcessError{ + TxHash: info.TxHash, + Error: fmt.Sprintf("invalid set link revoke, incorrect push data (%d)", len(info.PushData)), + }); err != nil { + return fmt.Errorf("error saving process error memo link revoke incorrect push data; %w", err) + } + return nil + } + if len(info.PushData[1]) != memo.TxHashLength { + if err := item.LogProcessError(&item.ProcessError{ + TxHash: info.TxHash, + Error: fmt.Sprintf("error link revoke accept tx hash incorrect length: %d", len(info.PushData[1])), + }); err != nil { + return fmt.Errorf("error saving process error memo link revoke accept tx hash; %w", err) + } + return nil + } + var acceptTxHash chainhash.Hash + copy(acceptTxHash[:], jutil.ByteReverse(info.PushData[1])) + var message string + if len(info.PushData) > 2 { + message = string(info.PushData[2]) + } + var linkRevoke = &dbMemo.LinkRevoke{ + TxHash: info.TxHash, + Addr: info.Addr, + AcceptTxHash: acceptTxHash, + Message: message, + } + var linkRevoked = &dbMemo.LinkRevoked{ + TxHash: info.TxHash, + AcceptTxHash: acceptTxHash, + } + if err := db.Save([]db.Object{linkRevoke, linkRevoked}); err != nil { + return fmt.Errorf("error saving db lock memo link revoke object; %w", err) + } + return nil + }, +}