103 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package main
 | 
						|
 | 
						|
import "os"
 | 
						|
import "fmt"
 | 
						|
import "time"
 | 
						|
import "bufio"
 | 
						|
import "context"
 | 
						|
import "crypto/tls"
 | 
						|
import "git.tebibyte.media/sashakoshka/hopp"
 | 
						|
import "git.tebibyte.media/sashakoshka/hopp/examples/chat"
 | 
						|
 | 
						|
func main() {
 | 
						|
	name := os.Args[0]
 | 
						|
	if len(os.Args) != 3 && len(os.Args) != 4 {
 | 
						|
		fmt.Fprintf(os.Stderr, "Usage: %s HOST:PORT ROOM [NICKNAME]\n", name)
 | 
						|
		os.Exit(2)
 | 
						|
	}
 | 
						|
	address := os.Args[1]
 | 
						|
	room    := os.Args[2]
 | 
						|
	var nickname hopp.Option[string]; if len(os.Args) >= 4 {
 | 
						|
		nickname = hopp.O(os.Args[3])
 | 
						|
	}
 | 
						|
	trans, err := join(address, room, nickname)
 | 
						|
	handleErr(1, err)
 | 
						|
	go func() {
 | 
						|
		reader := bufio.NewReader(os.Stdin)
 | 
						|
		for {
 | 
						|
			line, err := reader.ReadString('\n')
 | 
						|
			if err != nil { break }
 | 
						|
			send(trans, line)
 | 
						|
		}
 | 
						|
	}()
 | 
						|
	for {
 | 
						|
		message, err := chat.Receive(trans)
 | 
						|
		handleErr(1, err)
 | 
						|
		switch message := message.(type) {
 | 
						|
		case *chat.MessageChat:
 | 
						|
			nickname := "Anonymous"
 | 
						|
			if value, ok := message.Nickname.Get(); ok {
 | 
						|
				nickname = value
 | 
						|
			}
 | 
						|
			fmt.Fprintf(os.Stdout, "%s: %s\n", nickname, message.Content)
 | 
						|
		case *chat.MessageJoinNotify:
 | 
						|
			fmt.Fprintf(os.Stdout, "(i) %s joined the room\n", message.Nickname)
 | 
						|
		case *chat.MessageLeaveNotify:
 | 
						|
			fmt.Fprintf(os.Stdout, "(i) %s left the room\n", message.Nickname)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func join(address string, room string, nickname hopp.Option[string]) (hopp.Trans, error) {
 | 
						|
	ctx, done := context.WithTimeout(context.Background(), 16 * time.Second)
 | 
						|
	defer done()
 | 
						|
	dialer := hopp.Dialer {
 | 
						|
		TLSConfig: &tls.Config {
 | 
						|
			// don't actually do this in real life
 | 
						|
			InsecureSkipVerify: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
	conn, err := dialer.Dial(ctx, "quic", address)
 | 
						|
	if err != nil { return nil, err }
 | 
						|
 | 
						|
	err = updateProfile(conn, nickname)
 | 
						|
	if err != nil { return nil, err }
 | 
						|
	
 | 
						|
	transRoom, err := conn.OpenTrans()
 | 
						|
	if err != nil { return nil, err }
 | 
						|
	err = chat.Send(transRoom, &chat.MessageJoin {
 | 
						|
		Room: room,
 | 
						|
	})
 | 
						|
	if err != nil { return nil, err }
 | 
						|
	return transRoom, nil
 | 
						|
}
 | 
						|
 | 
						|
func send(trans hopp.Trans, content string) error {
 | 
						|
	return chat.Send(trans, &chat.MessageChat {
 | 
						|
		Content: content,
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func updateProfile(conn hopp.Conn, nickname hopp.Option[string]) error {
 | 
						|
	trans, err := conn.OpenTrans()
 | 
						|
	if err != nil { return err }
 | 
						|
	defer trans.Close()
 | 
						|
	err = chat.Send(trans, &chat.MessageUpdateProfile {
 | 
						|
		Nickname: nickname,
 | 
						|
	})
 | 
						|
	if err != nil { return err }
 | 
						|
	message, err := chat.Receive(trans)
 | 
						|
	if err != nil { return err }
 | 
						|
	switch message := message.(type) {
 | 
						|
	case *chat.MessageError: return message
 | 
						|
	default:                 return nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func handleErr(code int, err error) {
 | 
						|
	if err != nil {
 | 
						|
		fmt.Fprintf(os.Stderr, "%s: %v\n", os.Args[0], err)
 | 
						|
		os.Exit(code)
 | 
						|
	}
 | 
						|
}
 |