Reply with errors
This commit is contained in:
		
							parent
							
								
									6468955c23
								
							
						
					
					
						commit
						516478d258
					
				@ -730,12 +730,12 @@ func getXY(position string) (int, int, error) {
 | 
			
		||||
	posX = runes[0]
 | 
			
		||||
	posY = runes[1]
 | 
			
		||||
 | 
			
		||||
	if posX < 'a' && posX > 'h' {
 | 
			
		||||
		return -1, -1, fmt.Errorf("invalid posX: %s", position)
 | 
			
		||||
	if posX < 'a' || posX > 'h' {
 | 
			
		||||
		return -1, -1, fmt.Errorf("invalid move: %s", position)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if posY < '1' && posY > '8' {
 | 
			
		||||
		return -1, -1, fmt.Errorf("invalid posY: %s", position)
 | 
			
		||||
	if posY < '1' || posY > '8' {
 | 
			
		||||
		return -1, -1, fmt.Errorf("invalid move: %s", position)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// image origin (0,0) is at top-left corner (a8)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								db/db.go
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								db/db.go
									
									
									
									
									
								
							@ -57,8 +57,9 @@ func ItemHasReply(parentId int, userId int) (bool, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func InsertItem(item *sn.Item) error {
 | 
			
		||||
	if _, err := db.Exec(
 | 
			
		||||
		`INSERT INTO items(id, user_id, text, parent_id) VALUES (?, ?, ?, NULLIF(?, 0))`,
 | 
			
		||||
	if _, err := db.Exec(``+
 | 
			
		||||
		`INSERT INTO items(id, user_id, text, parent_id) VALUES (?, ?, ?, NULLIF(?, 0)) `+
 | 
			
		||||
		`ON CONFLICT DO UPDATE SET text = EXCLUDED.text, updated_at = CURRENT_TIMESTAMP`,
 | 
			
		||||
		item.Id, item.User.Id, item.Text, item.ParentId); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										237
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										237
									
								
								main.go
									
									
									
									
									
								
							@ -33,7 +33,7 @@ func tickGameStart(c *sn.Client) {
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if mentions, err = c.Mentions(); err != nil {
 | 
			
		||||
		log.Printf("mentions error: %v\n", err)
 | 
			
		||||
		log.Printf("failed to fetch mentions: %v\n", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -42,53 +42,23 @@ func tickGameStart(c *sn.Client) {
 | 
			
		||||
	for _, n := range mentions {
 | 
			
		||||
 | 
			
		||||
		if exists, err := db.ItemHasReply(n.Item.Id, meId); err != nil {
 | 
			
		||||
			log.Printf("error during game start check: %v\n", err)
 | 
			
		||||
			log.Printf("failed to check for existing reply to game start in item %d: %v\n", n.Item.Id, err)
 | 
			
		||||
			continue
 | 
			
		||||
		} else if exists {
 | 
			
		||||
			// TODO: check if move changed
 | 
			
		||||
			log.Printf("game start already exists: id=%d\n", n.Item.Id)
 | 
			
		||||
			log.Printf("reply to game start in item %d already exists\n", n.Item.Id)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		move := strings.Trim(strings.ReplaceAll(n.Item.Text, "@chess", ""), " ")
 | 
			
		||||
 | 
			
		||||
		var b *chess.Board
 | 
			
		||||
		if b, err = chess.NewGame(move); err != nil {
 | 
			
		||||
			log.Printf("error creating new game: %v: id=%d\n", err, n.Item.Id)
 | 
			
		||||
			continue
 | 
			
		||||
		if err = handleGameStart(&n.Item); err != nil {
 | 
			
		||||
			if _, err2 := createComment(n.Item.Id, fmt.Sprintf("`%v`", err)); err2 != nil {
 | 
			
		||||
				log.Printf("failed to reply with error to item %d: %v\n", n.Item.Id, err2)
 | 
			
		||||
			} else {
 | 
			
		||||
				log.Printf("replied to game start in item %d with error: %v\n", n.Item.Id, err)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			log.Printf("started new game via item %d\n", n.Item.Id)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		img := b.Image()
 | 
			
		||||
		var imgUrl string
 | 
			
		||||
		if imgUrl, err = c.UploadImage(img); err != nil {
 | 
			
		||||
			log.Printf("error uploading image: %v\n", err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		n.Item.ParentId = 0
 | 
			
		||||
		if err = db.InsertItem(&n.Item); err != nil {
 | 
			
		||||
			log.Printf("error inserting item into db: %v: id=%d\n", err, n.Item.Id)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		text := strings.Trim(fmt.Sprintf("%s\n\n%s", b.AlgebraicNotation(), imgUrl), " ")
 | 
			
		||||
		var cId int
 | 
			
		||||
		if cId, err = c.CreateComment(n.Item.Id, text); err != nil {
 | 
			
		||||
			log.Printf("error creating reply: %v\n", err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var item *sn.Item
 | 
			
		||||
		if item, err = c.Item(cId); err != nil {
 | 
			
		||||
			log.Printf("error fetching item: %v: id=%d\n", cId)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if err = db.InsertItem(item); err != nil {
 | 
			
		||||
			log.Printf("error inserting item into db: %v: id=%d\n", err, item.Id)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log.Printf("started new game: id=%d\n", n.Item.Id)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -99,7 +69,7 @@ func tickGameProgress(c *sn.Client) {
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if replies, err = c.Replies(); err != nil {
 | 
			
		||||
		log.Printf("replies error: %v\n", err)
 | 
			
		||||
		log.Printf("failed to fetch replies: %v\n", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -108,75 +78,134 @@ func tickGameProgress(c *sn.Client) {
 | 
			
		||||
	for _, n := range replies {
 | 
			
		||||
 | 
			
		||||
		if exists, err := db.ItemHasReply(n.Item.Id, meId); err != nil {
 | 
			
		||||
			log.Printf("error during game update check: %v\n", err)
 | 
			
		||||
			log.Printf("failed to check for existing reply to game update in item %d: %v\n", n.Item.Id, err)
 | 
			
		||||
			continue
 | 
			
		||||
		} else if exists {
 | 
			
		||||
			// TODO: check if move changed
 | 
			
		||||
			log.Printf("game update already exists: id=%d\n", n.Item.Id)
 | 
			
		||||
			log.Printf("reply to game update in item %d already exists\n", n.Item.Id)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var thread []sn.Item
 | 
			
		||||
		if thread, err = db.GetThread(n.Item.ParentId); err != nil {
 | 
			
		||||
			log.Printf("error fetching thread: %v: id=%d\n", err, n.Item.ParentId)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		b := chess.NewBoard()
 | 
			
		||||
		// TODO: better parsing of moves in replies using regexp for example or enforce a specific format
 | 
			
		||||
		// since players might include more than just the move in their replies
 | 
			
		||||
		move := strings.Trim(n.Item.Text, " ")
 | 
			
		||||
		for _, item := range thread {
 | 
			
		||||
			if item.User.Id == meId {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			moves := strings.Trim(strings.ReplaceAll(item.Text, "@chess", ""), " ")
 | 
			
		||||
			if err = b.Parse(moves); err != nil {
 | 
			
		||||
				log.Printf("error moving piece: %v: id=%d\n", err, item.Id)
 | 
			
		||||
				break
 | 
			
		||||
		if err = handleGameProgress(&n.Item); err != nil {
 | 
			
		||||
			if _, err2 := createComment(n.Item.Id, fmt.Sprintf("`%v`", err)); err2 != nil {
 | 
			
		||||
				log.Printf("failed to reply with error to item %d: %v\n", n.Item.Id, err2)
 | 
			
		||||
			} else {
 | 
			
		||||
				log.Printf("replied to game start in item %d with error: %v\n", n.Item.Id, err)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			log.Printf("updated game via item %d\n", n.Item.Id)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// continue with next reply if the thread loop failed
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err = b.Parse(move); err != nil {
 | 
			
		||||
			log.Printf("error moving piece: %v: id=%d\n", err, n.Item.ParentId)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		img := b.Image()
 | 
			
		||||
		var imgUrl string
 | 
			
		||||
		if imgUrl, err = c.UploadImage(img); err != nil {
 | 
			
		||||
			log.Printf("error uploading image: %v\n", err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err = db.InsertItem(&n.Item); err != nil {
 | 
			
		||||
			log.Printf("error inserting item into db: %v: id=%d\n", err, n.Item.Id)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		text := fmt.Sprintf("`%s`\n\n%s", b.AlgebraicNotation(), imgUrl)
 | 
			
		||||
		var cId int
 | 
			
		||||
		if cId, err = c.CreateComment(n.Item.Id, text); err != nil {
 | 
			
		||||
			log.Printf("error creating reply: %v\n", err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var item *sn.Item
 | 
			
		||||
		if item, err = c.Item(cId); err != nil {
 | 
			
		||||
			log.Printf("error fetching item: %v: id=%d\n", cId)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if err = db.InsertItem(item); err != nil {
 | 
			
		||||
			log.Printf("error inserting item into db: %v: id=%d\n", err, item.Id)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log.Printf("continued game: move=%s id=%d\n", move, cId)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handleGameStart(req *sn.Item) error {
 | 
			
		||||
	var (
 | 
			
		||||
		move   = strings.Trim(strings.ReplaceAll(req.Text, "@chess", ""), " ")
 | 
			
		||||
		b      *chess.Board
 | 
			
		||||
		imgUrl string
 | 
			
		||||
		res    string
 | 
			
		||||
		err    error
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// Immediately save game start request to db so we can store our reply to it in case of error.
 | 
			
		||||
	// We set parentId to 0 such that parent_id will be NULL in the db and not hit foreign key constraints.
 | 
			
		||||
	req.ParentId = 0
 | 
			
		||||
 | 
			
		||||
	if err = db.InsertItem(req); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to insert item %d into db: %v\n", req.Id, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// create board with initial move(s)
 | 
			
		||||
	if b, err = chess.NewGame(move); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to create new game from item %d: %v\n", req.Id, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// upload image of board
 | 
			
		||||
	if imgUrl, err = c.UploadImage(b.Image()); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to upload image for item %d: %v\n", req.Id, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// reply with algebraic notation and image
 | 
			
		||||
	res = strings.Trim(fmt.Sprintf("%s\n\n%s", b.AlgebraicNotation(), imgUrl), " ")
 | 
			
		||||
	if _, err = createComment(req.Id, res); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to reply to item %d: %v\n", req.Id, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handleGameProgress(req *sn.Item) error {
 | 
			
		||||
	var (
 | 
			
		||||
		thread []sn.Item
 | 
			
		||||
		b             = chess.NewBoard()
 | 
			
		||||
		move   string = strings.Trim(req.Text, " ")
 | 
			
		||||
		imgUrl string
 | 
			
		||||
		res    string
 | 
			
		||||
		err    error
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// immediately save game update request to db so we can store our reply to it in case of error
 | 
			
		||||
	if err = db.InsertItem(req); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to insert item %d into db: %v\n", req.Id, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// fetch thread to reconstruct all moves so far
 | 
			
		||||
	if thread, err = db.GetThread(req.ParentId); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to fetch thread for item %d: %v\n", req.ParentId, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, item := range thread {
 | 
			
		||||
		if item.User.Id == meId {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// TODO: better parsing of moves in replies using regexp for example or enforce a specific format
 | 
			
		||||
		// since players might include more than just the move in their replies
 | 
			
		||||
		moves := strings.Trim(strings.ReplaceAll(item.Text, "@chess", ""), " ")
 | 
			
		||||
 | 
			
		||||
		// parse and execute existing moves
 | 
			
		||||
		if err = b.Parse(moves); err != nil {
 | 
			
		||||
			return fmt.Errorf("failed to parse move %s: %v\n", moves, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// parse and execute new move
 | 
			
		||||
	if err = b.Parse(move); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to parse move %s: %v\n", move, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// upload image of updated board
 | 
			
		||||
	if imgUrl, err = c.UploadImage(b.Image()); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to upload image for item %d: %v\n", req.Id, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// reply with algebraic notation and image
 | 
			
		||||
	res = strings.Trim(fmt.Sprintf("%s\n\n%s", b.AlgebraicNotation(), imgUrl), " ")
 | 
			
		||||
	if _, err = createComment(req.Id, res); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to reply to item %d: %v\n", req.Id, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createComment(parentId int, text string) (*sn.Item, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		commentId int
 | 
			
		||||
		err       error
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if commentId, err = c.CreateComment(parentId, text); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("failed to reply to item %d: %v\n", parentId, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var comment *sn.Item
 | 
			
		||||
	if comment, err = c.Item(commentId); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("failed to fetch item %d: %v\n", commentId, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = db.InsertItem(comment); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("failed to insert item %d into db: %v\n", err, comment.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return comment, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user