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