package frontapi import ( "context" genCharacter "crossnokaye-interview-assignment/services/character/gen/character" genCharacterClient "crossnokaye-interview-assignment/services/character/gen/grpc/character/client" front "crossnokaye-interview-assignment/services/front/gen/front" genInventoryClient "crossnokaye-interview-assignment/services/inventory/gen/grpc/inventory/client" genInventory "crossnokaye-interview-assignment/services/inventory/gen/inventory" genItemClient "crossnokaye-interview-assignment/services/item/gen/grpc/item/client" genItem "crossnokaye-interview-assignment/services/item/gen/item" "fmt" "github.com/golang/protobuf/ptypes/empty" goa "goa.design/goa/v3/pkg" "google.golang.org/grpc" "log" ) type itemClient struct { getItem goa.Endpoint listItems goa.Endpoint createItem goa.Endpoint updateItem goa.Endpoint deleteItem goa.Endpoint } type characterClient struct { getCharacter goa.Endpoint listCharacters goa.Endpoint createCharacter goa.Endpoint updateCharacter goa.Endpoint deleteCharacter goa.Endpoint } type inventoryClient struct { addItem goa.Endpoint removeItem goa.Endpoint removeAll goa.Endpoint listInventoryItems goa.Endpoint listCharactersWithItem goa.Endpoint } // front service example implementation. // The example methods log the requests and return zero values. type frontsrvc struct { logger *log.Logger itemClient *itemClient characterClient *characterClient inventoryClient *inventoryClient } // NewFront returns the front service implementation. func NewFront(logger *log.Logger, itemClientConnection *grpc.ClientConn, characterClientConnection *grpc.ClientConn, inventoryClientConnection *grpc.ClientConn) front.Service { newItemClient := genItemClient.NewClient(itemClientConnection) newCharacterClient := genCharacterClient.NewClient(characterClientConnection) newInventoryClient := genInventoryClient.NewClient(inventoryClientConnection) return &frontsrvc{logger: logger, itemClient: &itemClient{ newItemClient.GetItem(), newItemClient.ListItems(), newItemClient.CreateItem(), newItemClient.UpdateItem(), newItemClient.DeleteItem()}, characterClient: &characterClient{ newCharacterClient.GetCharacter(), newCharacterClient.ListCharacters(), newCharacterClient.CreateCharacter(), newCharacterClient.UpdateCharacter(), newCharacterClient.DeleteCharacter()}, inventoryClient: &inventoryClient{ newInventoryClient.AddItem(), newInventoryClient.RemoveItem(), newInventoryClient.RemoveAll(), newInventoryClient.ListInventory(), newInventoryClient.ListCharactersWithItem(), }} } // GetItem implements getItem. func (s *frontsrvc) GetItem(ctx context.Context, name string) (res *front.Item, err error) { s.logger.Print("front.getItem") getItemResponse, err := s.itemClient.getItem(ctx, &genItem.GetItemPayload{Name: &name}) if err != nil { return nil, err } item := getItemResponse.(*genItem.Item) res = (*front.Item)(item) return } func (s *frontsrvc) ListItems(ctx context.Context) (res []*front.Item, err error) { s.logger.Print("front.listItems") listItemsResponse, err := s.itemClient.listItems(ctx, &genItem.ListItemsPayload{}) if err != nil { return nil, err } items := listItemsResponse.([]*genItem.Item) for _, itemToReturn := range items { res = append(res, (*front.Item)(itemToReturn)) } return } // CreateItem implements createItem. func (s *frontsrvc) CreateItem(ctx context.Context, itemPayload *front.Item) (res *front.Item, err error) { s.logger.Print("front.createItem") createItemResponse, err := s.itemClient.createItem(ctx, (*genItem.Item)(itemPayload)) if err != nil { return nil, err } item := createItemResponse.(*genItem.Item) res = (*front.Item)(item) return } // UpdateItem implements updateItem. func (s *frontsrvc) UpdateItem(ctx context.Context, itemPayload *front.Item) (res *front.Item, err error) { s.logger.Print("front.updateItem") updateItemResponse, err := s.itemClient.updateItem(ctx, (*genItem.Item)(itemPayload)) if err != nil { return nil, err } item := updateItemResponse.(*genItem.Item) res = (*front.Item)(item) return } // DeleteItem implements deleteItem. func (s *frontsrvc) DeleteItem(ctx context.Context, name string) (err error) { s.logger.Print("front.deleteItem") characters, err := s.getCharactersUsingItem(ctx, name) if err != nil { return err } if len(characters) > 0 { return front.MakeBadRequest(fmt.Errorf("item '%s' is referenced by character(s) %v", name, characters)) } _, err = s.itemClient.deleteItem(ctx, &genItem.DeleteItemPayload{Name: &name}) if err != nil { return err } return } // GetCharacter implements getCharacter. func (s *frontsrvc) GetCharacter(ctx context.Context, name string) (res *front.Character, err error) { s.logger.Print("front.getCharacter") getCharacterResponse, err := s.characterClient.getCharacter(ctx, &genCharacter.GetCharacterPayload{Name: &name}) if err != nil { return nil, err } character := getCharacterResponse.(*genCharacter.Character) res = (*front.Character)(character) return } func (s *frontsrvc) ListCharacters(ctx context.Context) (res []*front.Character, err error) { s.logger.Print("front.listCharacters") listCharactersResponse, err := s.characterClient.listCharacters(ctx, empty.Empty{}) if err != nil { return nil, err } characters := listCharactersResponse.([]*genCharacter.Character) for _, itemToReturn := range characters { res = append(res, (*front.Character)(itemToReturn)) } return } // CreateCharacter implements createCharacter. func (s *frontsrvc) CreateCharacter(ctx context.Context, characterPayload *front.Character) (res *front.Character, err error) { s.logger.Print("front.createCharacter") createCharacterResponse, err := s.characterClient.createCharacter(ctx, (*genCharacter.Character)(characterPayload)) if err != nil { return nil, err } character := createCharacterResponse.(*genCharacter.Character) res = (*front.Character)(character) return } // UpdateCharacter implements updateCharacter. func (s *frontsrvc) UpdateCharacter(ctx context.Context, characterPayload *front.Character) (res *front.Character, err error) { s.logger.Print("front.updateCharacter") updateCharacterResponse, err := s.characterClient.updateCharacter(ctx, (*genCharacter.Character)(characterPayload)) if err != nil { return nil, err } character := updateCharacterResponse.(*genCharacter.Character) res = (*front.Character)(character) return } // DeleteCharacter implements deleteCharacter. func (s *frontsrvc) DeleteCharacter(ctx context.Context, name string) (err error) { s.logger.Print("front.deleteCharacter") _, err = s.characterClient.deleteCharacter(ctx, &genCharacter.DeleteCharacterPayload{Name: &name}) if err != nil { return err } _, err = s.inventoryClient.removeAll(ctx, &genInventory.RemoveAllPayload{CharacterName: &name}) if err != nil { return err } return } // AddItemToInventory implements addItemToInventory. func (s *frontsrvc) AddItemToInventory(ctx context.Context, inventoryRecordPayload *front.InventoryRecord) (err error) { s.logger.Print("front.addItemToInventory") err = s.checkItemAndCharacter(ctx, inventoryRecordPayload) if err != nil { return err } _, err = s.inventoryClient.addItem(ctx, (*genInventory.InventoryRecord)(inventoryRecordPayload)) if err != nil { return err } return } // RemoveItemFromInventory implements removeItemFromInventory. func (s *frontsrvc) RemoveItemFromInventory(ctx context.Context, inventoryRecordPayload *front.InventoryRecord) (err error) { s.logger.Print("front.removeItemFromInventory") err = s.checkItemAndCharacter(ctx, inventoryRecordPayload) if err != nil { return err } _, err = s.inventoryClient.removeItem(ctx, (*genInventory.InventoryRecord)(inventoryRecordPayload)) if err != nil { return err } return } func (s *frontsrvc) ListInventoryItems(ctx context.Context, listInventoryItemsPayload *front.ListInventoryItemsPayload) (res []*front.Item, err error) { listInventoryResponse, err := s.inventoryClient.listInventoryItems(ctx, &genInventory.ListInventoryPayload{CharacterName: listInventoryItemsPayload.CharacterName}) if err != nil { return nil, err } itemNames := listInventoryResponse.([]string) items, err := s.getItemsByName(ctx, itemNames) if err != nil { return nil, err } for _, value := range items { res = append(res, (*front.Item)(value)) } return } func (s *frontsrvc) getCharactersUsingItem(ctx context.Context, itemName string) (characters []string, err error) { characterResponse, err := s.inventoryClient.listCharactersWithItem(ctx, &genInventory.ListCharactersWithItemPayload{ItemName: &itemName}) if err != nil { return nil, err } return characterResponse.([]string), nil } func (s *frontsrvc) checkItemAndCharacter(ctx context.Context, inventoryRecord *front.InventoryRecord) (err error) { getItemResponse, err := s.itemClient.getItem(ctx, &genItem.GetItemPayload{Name: &inventoryRecord.ItemName}) if err != nil { return err } if getItemResponse.(*genItem.Item) == nil { return front.MakeNotFound(fmt.Errorf("item '%s' not found", inventoryRecord.ItemName)) } getCharacterResponse, err := s.characterClient.getCharacter(ctx, &genCharacter.GetCharacterPayload{Name: &inventoryRecord.CharacterName}) if err != nil { return err } if getCharacterResponse.(*genCharacter.Character) == nil { return front.MakeNotFound(fmt.Errorf("character '%s' not found", inventoryRecord.CharacterName)) } return } func (s *frontsrvc) getItemsByName(ctx context.Context, itemNames []string) (items []*genItem.Item, err error) { itemResponse, err := s.itemClient.listItems(ctx, &genItem.ListItemsPayload{NameFilter: itemNames}) if err != nil { return nil, err } items = itemResponse.([]*genItem.Item) return }