blob: 29eb1034e96e9ad5c6f73856265789a75169d505 [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 "runtime"
12
13 "github.com/mongodb/mongo-go-driver/version"
14 "github.com/mongodb/mongo-go-driver/x/bsonx"
15 "github.com/mongodb/mongo-go-driver/x/network/address"
16 "github.com/mongodb/mongo-go-driver/x/network/description"
17 "github.com/mongodb/mongo-go-driver/x/network/result"
18 "github.com/mongodb/mongo-go-driver/x/network/wiremessage"
19)
20
21// Handshake represents a generic MongoDB Handshake. It calls isMaster and
22// buildInfo.
23//
24// The isMaster and buildInfo commands are used to build a server description.
25type Handshake struct {
26 Client bsonx.Doc
27 Compressors []string
28 SaslSupportedMechs string
29
30 ismstr result.IsMaster
31 err error
32}
33
34// Encode will encode the handshake commands into a wire message containing isMaster
35func (h *Handshake) Encode() (wiremessage.WireMessage, error) {
36 var wm wiremessage.WireMessage
37 ismstr, err := (&IsMaster{
38 Client: h.Client,
39 Compressors: h.Compressors,
40 SaslSupportedMechs: h.SaslSupportedMechs,
41 }).Encode()
42 if err != nil {
43 return wm, err
44 }
45
46 wm = ismstr
47 return wm, nil
48}
49
50// Decode will decode the wire messages.
51// Errors during decoding are deferred until either the Result or Err methods
52// are called.
53func (h *Handshake) Decode(wm wiremessage.WireMessage) *Handshake {
54 h.ismstr, h.err = (&IsMaster{}).Decode(wm).Result()
55 if h.err != nil {
56 return h
57 }
58 return h
59}
60
61// Result returns the result of decoded wire messages.
62func (h *Handshake) Result(addr address.Address) (description.Server, error) {
63 if h.err != nil {
64 return description.Server{}, h.err
65 }
66 return description.NewServer(addr, h.ismstr), nil
67}
68
69// Err returns the error set on this Handshake.
70func (h *Handshake) Err() error { return h.err }
71
72// Handshake implements the connection.Handshaker interface. It is identical
73// to the RoundTrip methods on other types in this package. It will execute
74// the isMaster command.
75func (h *Handshake) Handshake(ctx context.Context, addr address.Address, rw wiremessage.ReadWriter) (description.Server, error) {
76 wm, err := h.Encode()
77 if err != nil {
78 return description.Server{}, err
79 }
80
81 err = rw.WriteWireMessage(ctx, wm)
82 if err != nil {
83 return description.Server{}, err
84 }
85
86 wm, err = rw.ReadWireMessage(ctx)
87 if err != nil {
88 return description.Server{}, err
89 }
90 return h.Decode(wm).Result(addr)
91}
92
93// ClientDoc creates a client information document for use in an isMaster
94// command.
95func ClientDoc(app string) bsonx.Doc {
96 doc := bsonx.Doc{
97 {"driver",
98 bsonx.Document(bsonx.Doc{
99 {"name", bsonx.String("mongo-go-driver")},
100 {"version", bsonx.String(version.Driver)},
101 }),
102 },
103 {"os",
104 bsonx.Document(bsonx.Doc{
105 {"type", bsonx.String(runtime.GOOS)},
106 {"architecture", bsonx.String(runtime.GOARCH)},
107 }),
108 },
109 {"platform", bsonx.String(runtime.Version())},
110 }
111
112 if app != "" {
113 doc = append(doc, bsonx.Elem{"application", bsonx.Document(bsonx.Doc{{"name", bsonx.String(app)}})})
114 }
115
116 return doc
117}