OLD | NEW |
(Empty) | |
| 1 package main |
| 2 |
| 3 import ( |
| 4 "bufio" |
| 5 "fmt" |
| 6 "io" |
| 7 "io/ioutil" |
| 8 "log" |
| 9 "os" |
| 10 "strings" |
| 11 |
| 12 "github.com/golang/protobuf/proto" |
| 13 pb "github.com/google/protobuf/examples/tutorial" |
| 14 ) |
| 15 |
| 16 func promptForAddress(r io.Reader) (*pb.Person, error) { |
| 17 // A protocol buffer can be created like any struct. |
| 18 p := &pb.Person{} |
| 19 |
| 20 rd := bufio.NewReader(r) |
| 21 fmt.Print("Enter person ID number: ") |
| 22 // An int32 field in the .proto file is represented as an int32 field |
| 23 // in the generated Go struct. |
| 24 if _, err := fmt.Fscanf(rd, "%d\n", &p.Id); err != nil { |
| 25 return p, err |
| 26 } |
| 27 |
| 28 fmt.Print("Enter name: ") |
| 29 name, err := rd.ReadString('\n') |
| 30 if err != nil { |
| 31 return p, err |
| 32 } |
| 33 // A string field in the .proto file results in a string field in Go. |
| 34 // We trim the whitespace because rd.ReadString includes the trailing |
| 35 // newline character in its output. |
| 36 p.Name = strings.TrimSpace(name) |
| 37 |
| 38 fmt.Print("Enter email address (blank for none): ") |
| 39 email, err := rd.ReadString('\n') |
| 40 if err != nil { |
| 41 return p, err |
| 42 } |
| 43 p.Email = strings.TrimSpace(email) |
| 44 |
| 45 for { |
| 46 fmt.Print("Enter a phone number (or leave blank to finish): ") |
| 47 phone, err := rd.ReadString('\n') |
| 48 if err != nil { |
| 49 return p, err |
| 50 } |
| 51 phone = strings.TrimSpace(phone) |
| 52 if phone == "" { |
| 53 break |
| 54 } |
| 55 // The PhoneNumber message type is nested within the Person |
| 56 // message in the .proto file. This results in a Go struct |
| 57 // named using the name of the parent prefixed to the name of |
| 58 // the nested message. Just as with pb.Person, it can be |
| 59 // created like any other struct. |
| 60 pn := &pb.Person_PhoneNumber{ |
| 61 Number: phone, |
| 62 } |
| 63 |
| 64 fmt.Print("Is this a mobile, home, or work phone? ") |
| 65 ptype, err := rd.ReadString('\n') |
| 66 if err != nil { |
| 67 return p, err |
| 68 } |
| 69 ptype = strings.TrimSpace(ptype) |
| 70 |
| 71 // A proto enum results in a Go constant for each enum value. |
| 72 switch ptype { |
| 73 case "mobile": |
| 74 pn.Type = pb.Person_MOBILE |
| 75 case "home": |
| 76 pn.Type = pb.Person_HOME |
| 77 case "work": |
| 78 pn.Type = pb.Person_WORK |
| 79 default: |
| 80 fmt.Printf("Unknown phone type %q. Using default.\n", p
type) |
| 81 } |
| 82 |
| 83 // A repeated proto field maps to a slice field in Go. We can |
| 84 // append to it like any other slice. |
| 85 p.Phones = append(p.Phones, pn) |
| 86 } |
| 87 |
| 88 return p, nil |
| 89 } |
| 90 |
| 91 // Main reads the entire address book from a file, adds one person based on |
| 92 // user input, then writes it back out to the same file. |
| 93 func main() { |
| 94 if len(os.Args) != 2 { |
| 95 log.Fatalf("Usage: %s ADDRESS_BOOK_FILE\n", os.Args[0]) |
| 96 } |
| 97 fname := os.Args[1] |
| 98 |
| 99 // Read the existing address book. |
| 100 in, err := ioutil.ReadFile(fname) |
| 101 if err != nil { |
| 102 if os.IsNotExist(err) { |
| 103 fmt.Printf("%s: File not found. Creating new file.\n",
fname) |
| 104 } else { |
| 105 log.Fatalln("Error reading file:", err) |
| 106 } |
| 107 } |
| 108 |
| 109 // [START marshal_proto] |
| 110 book := &pb.AddressBook{} |
| 111 // [START_EXCLUDE] |
| 112 if err := proto.Unmarshal(in, book); err != nil { |
| 113 log.Fatalln("Failed to parse address book:", err) |
| 114 } |
| 115 |
| 116 // Add an address. |
| 117 addr, err := promptForAddress(os.Stdin) |
| 118 if err != nil { |
| 119 log.Fatalln("Error with address:", err) |
| 120 } |
| 121 book.People = append(book.People, addr) |
| 122 // [END_EXCLUDE] |
| 123 |
| 124 // Write the new address book back to disk. |
| 125 out, err := proto.Marshal(book) |
| 126 if err != nil { |
| 127 log.Fatalln("Failed to encode address book:", err) |
| 128 } |
| 129 if err := ioutil.WriteFile(fname, out, 0644); err != nil { |
| 130 log.Fatalln("Failed to write address book:", err) |
| 131 } |
| 132 // [END marshal_proto] |
| 133 } |
OLD | NEW |