blob: 6bd8d095c97339ba83129e6d15b2205d8c20309e [file] [log] [blame]
Don Newton379ae252019-04-01 12:17:06 -04001// Copyright (C) MongoDB, Inc. 2017-present.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7package command
8
9import (
10 "context"
11 "fmt"
12
13 "github.com/mongodb/mongo-go-driver/bson"
14 "github.com/mongodb/mongo-go-driver/x/bsonx"
15 "github.com/mongodb/mongo-go-driver/x/bsonx/bsoncore"
16 "github.com/mongodb/mongo-go-driver/x/network/result"
17 "github.com/mongodb/mongo-go-driver/x/network/wiremessage"
18)
19
20// IsMaster represents the isMaster command.
21//
22// The isMaster command is used for setting up a connection to MongoDB and
23// for monitoring a MongoDB server.
24//
25// Since IsMaster can only be run on a connection, there is no Dispatch method.
26type IsMaster struct {
27 Client bsonx.Doc
28 Compressors []string
29 SaslSupportedMechs string
30
31 err error
32 res result.IsMaster
33}
34
35// Encode will encode this command into a wire message for the given server description.
36func (im *IsMaster) Encode() (wiremessage.WireMessage, error) {
37 cmd := bsonx.Doc{{"isMaster", bsonx.Int32(1)}}
38 if im.Client != nil {
39 cmd = append(cmd, bsonx.Elem{"client", bsonx.Document(im.Client)})
40 }
41 if im.SaslSupportedMechs != "" {
42 cmd = append(cmd, bsonx.Elem{"saslSupportedMechs", bsonx.String(im.SaslSupportedMechs)})
43 }
44
45 // always send compressors even if empty slice
46 array := bsonx.Arr{}
47 for _, compressor := range im.Compressors {
48 array = append(array, bsonx.String(compressor))
49 }
50
51 cmd = append(cmd, bsonx.Elem{"compression", bsonx.Array(array)})
52
53 rdr, err := cmd.MarshalBSON()
54 if err != nil {
55 return nil, err
56 }
57 query := wiremessage.Query{
58 MsgHeader: wiremessage.Header{RequestID: wiremessage.NextRequestID()},
59 FullCollectionName: "admin.$cmd",
60 Flags: wiremessage.SlaveOK,
61 NumberToReturn: -1,
62 Query: rdr,
63 }
64 return query, nil
65}
66
67// Decode will decode the wire message using the provided server description. Errors during decoding
68// are deferred until either the Result or Err methods are called.
69func (im *IsMaster) Decode(wm wiremessage.WireMessage) *IsMaster {
70 reply, ok := wm.(wiremessage.Reply)
71 if !ok {
72 im.err = fmt.Errorf("unsupported response wiremessage type %T", wm)
73 return im
74 }
75 rdr, err := decodeCommandOpReply(reply)
76 if err != nil {
77 im.err = err
78 return im
79 }
80 err = bson.Unmarshal(rdr, &im.res)
81 if err != nil {
82 im.err = err
83 return im
84 }
85
86 // Reconstructs the $clusterTime doc after decode
87 if im.res.ClusterTime != nil {
88 im.res.ClusterTime = bsoncore.BuildDocument(nil, bsoncore.AppendDocumentElement(nil, "$clusterTime", im.res.ClusterTime))
89 }
90 return im
91}
92
93// Result returns the result of a decoded wire message and server description.
94func (im *IsMaster) Result() (result.IsMaster, error) {
95 if im.err != nil {
96 return result.IsMaster{}, im.err
97 }
98
99 return im.res, nil
100}
101
102// Err returns the error set on this command.
103func (im *IsMaster) Err() error { return im.err }
104
105// RoundTrip handles the execution of this command using the provided wiremessage.ReadWriter.
106func (im *IsMaster) RoundTrip(ctx context.Context, rw wiremessage.ReadWriter) (result.IsMaster, error) {
107 wm, err := im.Encode()
108 if err != nil {
109 return result.IsMaster{}, err
110 }
111
112 err = rw.WriteWireMessage(ctx, wm)
113 if err != nil {
114 return result.IsMaster{}, err
115 }
116 wm, err = rw.ReadWireMessage(ctx)
117 if err != nil {
118 return result.IsMaster{}, err
119 }
120 return im.Decode(wm).Result()
121}