Une semaine pour coder par soi même : Jour 2

Contrairement à hier, j'écris l'article au fil de l'eau.

Raccourcir la boucle

Bon pour ce second jour j'ai commencé par automatiser un poil la façon de tester le code. Pour le moment je lançais un netcat en écoute sur un port dans un terminal, puis je lançais le go run ircc.go. Sauf qu'à chaque fois que je le quittais, fallait retourner sur le term avec le netcat et le relancer… chiant.

Du coup premier truc de la journée : faire un micro-script shell pour lancer ça dans un tmux :

#! /bin/bash
Reload(){
        tmux send-keys -t .+ C-c
        tmux send-keys C-c
        tmux send-keys -t .+ nc Space -l Space -p Space 6667 Enter
        tmux send-keys go Space run Space ircc.go Enter
}

Loop(){
        while true
        do
                read -s -n 1 input
                Reload
        done
}

Loop

Il permet d'envoyer un Ctrl-c aux deux panes, puis de relancer le serveur et le programme en Go. La boucle permet de relancer ces actions en appuyant sur n'importe quelle touche comme ça c'est on ne peut plus simple.

Foutre des variables et virer le hardcode

Ouai c'était pas terrible du coup j'ai commencé à mettre tout pleins de variables. Déjà parceque c'est facile à faire, il suffit d'être méticuleux et de ne rien oublier. Pour commencer la journée c'est soft.

J'en ai également profité pour tenter de récupérer les arguments donnés au programme. Pour l'instant j'en ai pas spécialement besoin mais ça pourrait servir ensuite. Du coup j'en profite pour récupérer os.Args (en testant au préalable sa longueur). Je pourrai picorer cet exemple plus tard pour l'utiliser différemment.

Parser un peu mieux IRC

Bon pour l'instant c'était très très basique. Du coup je me suis attelé à faire ça un peu plus proprement.

Je suis donc parti dans l'idée de récupérer une chaîne de caractère et de l'éclater en plusieurs sous-chaîne (séparée par des espaces) pour ensuite comparer certains champs seulement.

En fonction de ça je déclenche des actions bidons pour le moment.

Se documenter

J'ai dégainé la RFC d'IRC car ça devenait indispensable sur certains points.

Les emmerdes

J'entrevois déjà pas mal de limitations dans ma façon de coder. Je me retrouve à balader certaines variables un peu partout (les conn, nick et compagnie). J'imagine qu'il y a moyen de faire autrement mais ça va être vite compliqué sinon.

Il me faut donc trouver le moyen de pouvoir écrire une fonction "envoyer_sur_IRC" qui soit appelable d'à peu près partout sans lui donner le socket et compagnie…

Le code maintenant

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"io"
	"strings"
	"time"
    )

func main() {

	var server string = "localhost"
	var port string = "6667"
	var channel string = "#lms"
	var nick string = "bab"
	var commander string = ":Lord!Lord@geeknode.fuckyeah"

	if len(os.Args) > 1 {
		server = os.Args[1]
	}

	conn, err := net.Dial("tcp",server+":"+port)
	go incoming(conn)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer conn.Close()
	connbuf := bufio.NewReader(conn)
	go io.Copy(conn, os.Stdin)

	initIrc(conn, nick, channel)

	for {
		msg, err := connbuf.ReadString('\n')
		if err != nil {
			break
		}
		fmt.Println("<< "+msg)
		parseIrc(msg,conn,commander,channel)
	}
	
}

// ------------------
// Côté IRC
// ------------------

func initIrc(conn net.Conn, nick string, channel string){
	fmt.Println("NICK "+nick+"\n")
	io.WriteString(conn,"NICK "+nick+"\n")
	fmt.Println("USER "+nick+"0.0.0.0 "+nick+" :"+nick+" bot\n")
	io.WriteString(conn,"USER "+nick+" 0.0.0.0 "+nick+" :"+nick+" bot\n")
	fmt.Println("JOIN "+channel+"\n")
	io.WriteString(conn,"JOIN "+channel+"\n")

}

func parseIrc(msg string,conn net.Conn, commander string, channel string){
	var elements []string = strings.Fields(msg)
	for i, element := range elements {
		fmt.Println( i,": "+element )

		if elements[1] == "421" {
			fmt.Println("!! Commande non reconnue par le serveur !!")
			break
		}

		if elements[0] == "PING" {
			fmt.Println(">> PONG "+strings.TrimPrefix(msg, "PING :"))
			io.WriteString(conn,"PONG "+strings.TrimPrefix(msg, "PING :"))
			break
		}

		if elements[1] == "JOIN" {
			fmt.Println("On a rejoin le salon "+strings.Trim(elements[2],":"))
			break
		}

		if elements[1] == "PART" {
			fmt.Println("On est parti de "+strings.Trim(elements[2],":"))
			break
		}
	}
    

}


func sendIrc(conn net.Conn,channel string, msg string){
	fmt.Println(">> PRIVMSG "+channel+" :"+msg)
	io.WriteString(conn,">> PRIVMSG "+channel+" :"+msg)

}

// ------------------
// Serveur en écoute
// ------------------

func incoming(outconn net.Conn){
	ln, err :=net.Listen("tcp",":4321")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	for {
		conn, err :=ln.Accept()
		if err != nil {
			fmt.Println(err)
			continue
		}
		go handleIncoming(conn, outconn)
	}
}

func handleIncoming(in net.Conn, out net.Conn){
	fmt.Println("Incoming from ",in.RemoteAddr())
	inbuf := bufio.NewReader(in)
	for {
    		inmsg, err := inbuf.ReadString('\n')
    		if err != nil {
			break
    		}
    		fmt.Println("<<]] "+inmsg)
    		io.WriteString(out,"PRIVMSG #lms :"+inmsg)
    		time.Sleep(500 * time.Millisecond)
	}
}