❤ 0 Auteur : Otruch
Logiciel : RPG Maker XP, VX et Ace
Nombre de scripts : 3
Bonjour à tous,
j'ai adapté le module réseau de SFML 2.3 pour le rendre compatible avec le RGSS. Testé sur RPG Maker XP, elle devrait fonctionner pour les autres. Cette implémentation est uniquement pour les scripteurs, elle ne vous servira à rien si vous ne savez pas scripter.
Ce module contient :
- socket TCP : permettent de communiquer avec un serveur TCP. La communication est lente, mais fiable. Elle permet par exemple d'implémenter un système de combat en ligne en tour par tour.
- socket UDP : permettent de communiquer avec un serveur UDP. La communication est rapide, mais peut avoir des erreurs. Elle permet par exemple de faire un salon avec plusieurs joueurs, afficher les coordonnées/mouvements de chaque joueur. Il peut y avoir des erreurs, seulement si on envoie les données à chaque frame, le joueur ne verra pas l'erreur.
- requête HTTP : permet de communiquer avec un serveur HTTP. Avant d'éviter tout amalgame, elle ne permet pas d'afficher des sites web, mais de lire leur contenu. Elle ne permet pas non plus de naviguer à travers un DOM à la façon de javascript, si vous voulez le coder c'est tout à votre honneur. Elle permettrait de façon simple d'enregistrer des données par exemple, si vous voulez faire un système de trophée, que chaque joueur peut regarder les trophées des autres sur un site web, vous envoyez la requête http et le serveur le stockera dans la base de donnée.
La seule limite de tout ça est donc votre imagination (et votre capacité à scripter, pas forcément évident le réseau).
Ce qui n'a pas encore été fait :
- requête FTP : permettrait de lire les fichiers d'un serveur FTP, on pourrait l'utiliser pour une mise à jour automatique. Ceci dit, j'hésite à le faire, car il faut bien gérer ses permissions du serveur, au risque de tout perdre, et ce n'est pas forcément évident. Donc si vous voulez le voir implémenté, faites le moi savoir par MP, sinon je ne le ferait pas spécialement.
Ces 3 fonctionnalités sont indépendantes l'une des autres, vous pouvez n'en installer qu'une ou deux selon vos envies. Cependant, pour ces 3, il vous faudra les mêmes dll fournis ci dessous.
Crédits :
Voici la liste des crédits (à mettre dans votre fiche de crédits, là où sont cités les auteurs, oui il faut ça quelque part " /> )
Développement de la bibliothèque C++ : SFML ( http://www.sfml-dev.org/ )
Intégration dans une DLL compatible avec RGSS : Otruch
Commun à toute fonctionnalité :
Pour tous, vous devez ajouter 3 dll à votre projet. Télécharger le .zip en cliquant ici.
Décompressez le, allez dans le dossier, et copiez les 3 dll (et non pas le dossier !), collez les dans la racine du projet. (la racine est l'élément principal, le dossier où il y a Game.exe).
La socket TCP
Installation
Créez un nouveau script avant le main et nommez le TcpSocket
Copiez y le code suivant :
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
| # TcpSocket : crée une socket TCP permettant de communiquer avec un serveur TCP
# Prérequis d'utilisation : il faut avoir dans le dossier racine de son projet
# les fichiers suivants : rgssnetwork.dll, sfml-network-2.dll, [url=https://www.rpg-maker.fr/divers/scripts/script501_rgssnetwork_sfml_system_2.zip]sfml-system-2.dll[/url]
# Crédits :
# Développement de la bibliothèque C++ : SFML ( [url=http://www.sfml-dev.org/]http://www.sfml-dev.org/[/url] )
# Intégration dans une DLL compatible avec RGSS : Otruch
class TcpSocket
# Contantes de status : donne une information de l'état de l'action effectuée
DONE = 0 # L'action a été effectuée avec succès
NOT_READY = 1 # La socket n'est pas prête à envoyer/recevoir des données
PARTIAL = 2 # La socket n'a envoyé qu'une portion de la donnée
DISCONNECTED = 3 # La socket s'est déconnectée
ERROR = 4 # Une erreur innatendue.
# Importation des fonctions de la DLL, à ne pas utiliser manuellement.
@@new = Win32API.new("rgssnetwork","RGSSNetworkTcpSocketAdd",["P"],"I")
@@connect = Win32API.new("rgssnetwork","RGSSNetworkTcpSocketConnect",["I","P","I"],"I")
@@connectTimeout = Win32API.new("rgssnetwork","RGSSNetworkTcpSocketConnectTimeout",["I","P","I","I"],"I")
@@setBlocking = Win32API.new("rgssnetwork","RGSSNetworkTcpSocketSetBlocking",["I","I"],"V")
@@send = Win32API.new("rgssnetwork","RGSSNetworkTcpSocketSend",["I","P","I"],"I")
@@receive = Win32API.new("rgssnetwork","RGSSNetworkTcpSocketReceive",["I","I"],"P")
@@disconnect = Win32API.new("rgssnetwork","RGSSNetworkTcpSocketDisconnect",["I"],"V")
@@delete = Win32API.new("rgssnetwork","RGSSNetworkTcpSocketDelete",["I"],"V")
# Constructeur à l'appel de TcpSocket.new
# [replaceZero] : String : paramètre optionnel. Pour des problèmes de compatibilités,
# le C++ remplace tout caractère '\0' par ce paramètre, ruby le reconvertit.
# si au grand jamais votre serveur veut envoyer [[[AntislashZero]]], il sera transformé en \0,
# si vous êtes dans ce rare cas, mettez en paramètre un code que vous n'utiliserez jamais
# sinon, laissez tel quel.
def initialize(replaceZero = "[[[AntislashZero]]]")
@replaceZero = replaceZero
@id = @@new.Call(replaceZero)
end
# Connecte la socket à l'addresse et au port demandés avec un timeout.
# Si le timeout n'est pas spécifié, ça sera la valeur par défaut de l'OS.
# host : String : addresse du serveur, peut être localhost, une adresse IP
# ou un nom de domaine
# port : entier positif : port du serveur à écouter.
# [timeout] : entier positif : timeout de la connection donné en millisecondes.
# return : Entier : donne l'état de la connection définit dans les constantes de status.
def connect(host,port,timeout = nil)
if timeout == nil then
status = @@connect.Call(@id,host,port)
else
status = @@connectTimeout.Call(@id,host,port,timeout)
end
return status
end
# Définit si la socket est bloquante ou non bloquante.
# Par défaut, la socket est bloquante.
# blocking : boolean : true pour bloquante, false pour non bloquante.
def setBlocking(blocking)
arg = blocking ? 1 : 0
@@setBlocking.Call(@id,arg)
end
# Envoie la donnée data à la socket connectée.
# data : String : donnée à envoyer. Pour envoyer des paquets binaires,
# référez vous à Array.pack et String.unpack.
#return : Entier : statut définit dans les constantes de status.
def send(data)
return @@send.Call(@id,data,data.length)
end
# Reçois les données en ayant pour maximum maxLength de caractères.
# maxLength : le nombre de données maximum à recevoir.
# return : String : la donnée reçue, si rien n'a été reçu, renvoie ""
def receive(maxLength)
data = @@receive.Call(@id,maxLength)
return data.gsub(@replaceZero,"\0")
end
# Déconnecte la socket du serveur.
def disconnect
@@disconnect.Call(@id)
end
# Destructeur de la socket,
# à utiliser impérativement lorsque vous n'en avez plus besoin ! Si vous ne le faites pas, cela génèrera des fuites de mémoires, certes invisibles pour l'utilisateur, mais se verrait bouffer sa RAM après 38 utilisations. Même après la fin du programme !
# fait appel à la méthode disconnect.
def destroy
@@delete.Call(@id)
end
end |
Manuel d'utilisation :
Pour plusieurs actions, on vous renverra un status, décrivant l'état de l'action, les status sont définit dans les constantes suivantes :
TcpSocket::DONE : L'action a été effectuée avec succès
TcpSocket::NOT_READY : La socket n'est pas prête à envoyer/recevoir des données
TcpSocket::PARTIAL : La socket n'a envoyé qu'une portion de la donnée
TcpSocket::DISCONNECTED : La socket s'est déconnectée
TcpSocket::ERROR : Une erreur innatendue.
Pour créer une socket,on fait socket = TcpSocket.new
Pour des raisons de compatibilité avec le C++, il a fallu faire une chaine par défaut qui soit remplacée par '\0'. la chaine par défaut est "[[[AntislashZero]]]". Si par malheur votre serveur devrait envoyer cette chaine, ça poserait problème. Dans ce cas très rare, choisissez une autre chaine et créez la socket comme ceci : socket = TcpSocket.new("monAutreChaine")
Ensuite, après l'avoir créé, il faut la connecter au TcpServer, on le fait comme ceci :
socket.connect(addresse,port). Addresse étant un String valant "localhost", le nom de domaine ou l'addresse IP du serveur. Port étant un entier valant le port auquel communiquer (il faut que ça soit le même sur le serveur).
On peut aussi préciser un timeout en troisième paramètre, un entier en millisecondes, si le timeout n'est pas précisé il prendra la valeur par défaut de l'OS.
La valeur de retour est un status décrivant l'état de la connexion.
par exemple pour une seconde, localhost au port 800 :
status = socket.connect("localhost",800,1000)
if status == TcpSocket::DONE
#...
À partir de là, une connexion est crée, les socket peuvent alors communiquer.
Avant de passer à la communication, il faut faire un truc d'important :
Après avoir terminé d'utiliser la socket, il faut IMPERATIVEMENT faire appel à socket.destroy
Si vous ne le faites pas, cela génèrera des fuites de mémoires, certes invisibles pour l'utilisateur, mais se verrait bouffer sa RAM après 38 utilisations. Même après la fin du programme !
La methode destroy fait appel à la méthode disconnect.
Pour déconnecter une socket (la méthode destroy le fait mais on sait jamais, des fois que vous voulez la connecter ailleurs), c'est comme ça :
socket.disconnect
Pour envoyer une donnée, on fait appel à la méthode send, on envoie une chaine de caractère en argument. La valeur de retour est le status décrivant l'état de l'envoi.
Par exemple, j'envoie coucou au serveur :
status = socket.send("coucou")
Pour recevoir des données, on fait appel à la méthode receive, en passant le maximum de charactères qu'on veut recevoir. La valeur de retour est un String envoyé par le serveur, si la réception a échoué, il envoie "". Par exemple, si je ne veux pas recevoir au délà de 200 caractères, je fais :
data = socket.receive(200)
Si on veut envoyer et recevoir des paquets binaires tels qu'une série d'entiers, il est sage d'utiliser les méthodes Array.pack et String.unpack, cf la documentation.
Par défaut, les socket sont bloquantes, cela veut dire que le programme attend, "freeze", tant que l'on a pas reçu de données. On peut les rendre non bloquantes, ce qui ferait que si la donnée n'est pas envoyée, on reçoit "" mais on continue le programme.
Pour changer ce mode, on utilise la méthode setBlocking, en argument un booleen valant true si bloquant, false sinon
Pour mettre ma socket non bloquante, je fais socket.setBlocking(false)
La socket UDP
Installation :
Ajoutez un nouveau script, avant le Main, nommez le UdpSocket, et copiez y ceci :
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
| # Udp : crée une socket UDP permettant de communiquer avec d'autres sockets UDP
# Prérequis d'utilisation : il faut avoir dans le dossier racine de son projet
# les fichiers suivants : rgssnetwork.dll, sfml-network-2.dll, sfml-system-2.dll
# Crédits :
# Développement de la bibliothèque C++ : SFML ( [url=http://www.sfml-dev.org/]http://www.sfml-dev.org/[/url] )
# Intégration dans une DLL compatible avec RGSS : Otruch
class UdpSocket
# Contantes de status : donne une information de l'état de l'action effectuée
DONE = 0 # L'action a été effectuée avec succès
NOT_READY = 1 # La socket n'est pas prête à envoyer/recevoir des données
PARTIAL = 2 # La socket n'a envoyé qu'une portion de la donnée
DISCONNECTED = 3 # La socket s'est déconnectée
ERROR = 4 # Une erreur innatendue.
# Importation des fonctions de la DLL, à ne pas utiliser manuellement.
@@new = Win32API.new("rgssnetwork","RGSSNetworkUdpSocketAdd",["P"],"I")
@@bind = Win32API.new("rgssnetwork","RGSSNetworkUdpSocketBind",["I","I"],"I")
@@send = Win32API.new("rgssnetwork","RGSSNetworkUdpSocketSend",["I","P","I","P","I"],"I")
@@receive = Win32API.new("rgssnetwork","RGSSNetworkUdpSocketReceive",["I","I"],"I")
@@getLastData = Win32API.new("rgssnetwork","RGSSNetworkUdpSocketgetLastData",["I"],"P")
@@getLastIp = Win32API.new("rgssnetwork","RGSSNetworkUdpSocketGetLastIp",["I"],"P")
@@getLastPort = Win32API.new("rgssnetwork","RGSSNetworkUdpSocketGetLastPort",["I"],"I")
@@setBlocking = Win32API.new("rgssnetwork","RGSSNetworkUdpSocketSetBlocking",["I","I"],"V")
@@unbind = Win32API.new("rgssnetwork","RGSSNetworkUdpSocketUnbind",["I"],"V")
@@delete = Win32API.new("rgssnetwork","RGSSNetworkUdpSocketDelete",["I"],"V")
# Constructeur à l'appel de UdpSocket.new
# [replaceZero] : String : paramètre optionnel. Pour des problèmes de compatibilités,
# le C++ remplace tout caractère '\0' par ce paramètre, ruby le reconvertit.
# si au grand jamais votre serveur veut envoyer [[[AntislashZero]]], il sera transformé en \0,
# si vous êtes dans ce rare cas, mettez en paramètre un code que vous n'utiliserez jamais
# sinon, laissez tel quel.
def initialize(replaceZero = "[[[AntislashZero]]]")
@replaceZero = replaceZero
@id = @@new.Call(replaceZero)
end
# Lie la socket à un port, une fois la socket liée, elle pourra recevoir des
# données via ce port.
# port : Entier positif : le port auquel la socket sera liée.
#return : Entier positif : return le status définit dans les constantes de status.
def bind(port)
return @@bind.Call(@id,port)
end
# Envoie les données data à l'adresse spécifiée, au port spécifié.
# data : String : donnée à envoyer. Pour envoyer des paquets binaires,
# référez vous à Array.pack et String.unpack.
# address : String : addresse à laquelle envoyer les données,
# peut être localhost, un nom de domaine ou une addresse IP.
# port : Entier positif : port auquel envoyer les données.
#return : Entier positif : return le status définit dans les constantes de status.
def send(data,address,port)
return @@send.Call(@id,data,data.length,address,port)
end
# Reçois les données en ayant pour maximum maxLength de caractères.
# maxLength : le nombre de données maximum à recevoir.
# return : Array : [status,data,address,port] si le status est UdpSocket::DONE
# ou Array : [status] si status est différent de UdpSocket::DONE
# status : Entier positif : return le status définit dans les constantes de status.
# data : String : donnée reçue
# address : addresse de la socket qui a envoyé la donnée
# port : port auquel est liée la socket qui a envoyé la donnée,
# utile pour envoyer des données, on utilisera ce port.
def receive(maxLength)
datas = []
status = @@receive.Call(@id,maxLength)
datas[0] = status
if status == DONE then
data = @@getLastData.Call(@id)
datas[1] = data.gsub(@replaceZero,"\0")
datas[2] = @@getLastIp.Call(@id)
datas[3] = @@getLastPort.Call(@id)
end
return datas
end
# Définit si la socket est bloquante ou non bloquante.
# Par défaut, la socket est bloquante.
# blocking : boolean : true pour bloquante, false pour non bloquante.
def setBlocking(blocking)
arg = blocking ? 1 : 0
@@setBlocking.Call(@id,arg)
end
# Délie la socket au port qu'elle écoutait,
# une fois appelée, elle ne pourra plus recevoir de données sur ce port.
def unbind
@@unbind.Call(@id)
end
# Destructeur de la socket,
# à utiliser impérativement lorsque vous n'en avez plus besoin !
# fait appel à la méthode unbind.
def destroy
@@delete.Call(@id)
end
end |
Manuel d'utilisation
Pour plusieurs actions, on vous renverra un status, décrivant l'état de l'action, les status sont définit dans les constantes suivantes :
UdpSocket::DONE : L'action a été effectuée avec succès
UdpSocket::NOT_READY : La socket n'est pas prête à envoyer/recevoir des données
UdpSocket::PARTIAL : La socket n'a envoyé qu'une portion de la donnée
UdpSocket::DISCONNECTED : La socket s'est déconnectée
UdpSocket::ERROR : Une erreur innatendue.
Pour créer une socket,on fait socket = UdpSocket.new
Pour des raisons de compatibilité avec le C++, il a fallu faire une chaine par défaut qui soit remplacée par '\0'. la chaine par défaut est "[[[AntislashZero]]]". Si par malheur votre serveur devrait envoyer cette chaine, ça poserait problème. Dans ce cas très rare, choisissez une autre chaine et créez la socket comme ceci : socket = UdpSocket.new("monAutreChaine")
Pour recevoir des données, il faut lier la socket à un port, cela se fait avec la méthode bind, avec pour argument le port, qui est un entier positif. La méthode renvoie le status qui décrit l'état de la connection.
exemple status = socket.bind(800)
Avant de passer à la communication, il faut faire un truc d'important :
Après avoir terminé d'utiliser la socket, il faut IMPERATIVEMENT faire appel à socket.destroy
Si vous ne le faites pas, cela génèrera des fuites de mémoires, certes invisibles pour l'utilisateur, mais se verrait bouffer sa RAM après 38 utilisations.Même après la fin du programme !
La methode destroy fait appel à la méthode unbind.
Pour délier la socket à un port, bien que la méthode destroy le fait, on peut toujours l'utiliser pour la relier à un autre port, on fait appel à la méthode unbind, comme ceci : socket.unbind
Pour envoyer des données à une autre socket udp, on fait appel à la méthode send, prenant en argument :
data : String qui sont les données sous forme de chaine de caractère
address : String : l'addresse de la socket, elle peut être "localhost", un nom de domaine, ou une addresse IP.
port : entier positif : le port à envoyer, celui qui est connecté à socket à laquelle communiquer. Elle peut être différente de celle où on est lié (ce qui est même conseillé car on risque de s'envoyer les données à soit même quand on travail en local.)
par exemple, je veux envoyer au localhost, la donnée "coucou" au port 800, je fais socket.send("coucou","localhost",800)
Pour recevoir des données, on fait appel à la méthode receive, prenant en argument maxLength, qui est le nombre de caractères maximum qu'on souhaite recevoir.
La socket retourne un Array comprenant :
- le status qui est l'état de la réception.
Si le status n'est pas égal à UdpSocket::DONE, ça s'arrête là,
--> donc renvoies [status]
si le status est égal à Udp::Socket::DONE, l'array comprend aussi :
- l'addresse IP de la socket qui envoie sous forme de chaine de caractère.
- le port qui est lié à la socket qui envoie, pour lui envoyer des données on utilisera donc ce port.
--> donc renvoies [status,address,port]
Si on veut envoyer et recevoir des paquets binaires tels qu'une série d'entiers, il est sage d'utiliser les méthodes Array.pack et String.unpack, cf la documentation.
Par défaut, les socket sont bloquantes, cela veut dire que le programme attend, "freeze", tant que l'on a pas reçu de données. On peut les rendre non bloquantes, ce qui ferait que si la donnée n'est pas envoyée, on reçoit "" mais on continue le programme.
Pour changer ce mode, on utilise la méthode setBlocking, en argument un booleen valant true si bloquant, false sinon
Pour mettre ma socket non bloquante, je fais socket.setBlocking(false)
La requête HTTP
Note : je n'ai testé que les méthodes GET et POST, et n'ai pas testé les header, parce que je n'y connais rien du tout, donc s'il y a un kwak, dites moi l'erreur et j'arrangerai ça.
Installation
Vous avez 2 scripts à ajouter.
Ajouter d'abord un premier script, avant le Main, nommez le HttpRequest et copiez y le code suivant :
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
| # HttpRequest : Classe représentant la requête HTTP.
# Prérequis d'utilisation : s'utilise avec HttpResponse
# voir les prérequis d'utilisation de HttpResponse
# Crédits :
# Développement de la bibliothèque C++ : SFML ( http://www.sfml-dev.org/ )
# Intégration dans une DLL compatible avec RGSS : Otruch
class HttpRequest
# Constantes de méthodes de la requête.
GET = 0
POST = 1
HEAD = 2
PUT = 3
DELETE = 4
# Attributs publiques, utiliser marequete.attribut = valeur pour modifier
# utiliser valeur = marequete.attribut pour lire la valeur.
# marequete étant l'objet requête, attribut étant l'attribut sans le :
attr_accessor :host # String : nom de domaine auquel envoyer (exemple : "google.fr")
attr_accessor :uri # String : url sans le nom de domaine, (exemple : "/image.png" pour image.png se situant dans la racine.
attr_accessor :method # Entier : méthode de la requête définit dans les constantes de méthodes.
attr_accessor :port # Entier positif : port sur lequel faire la requête.
# Attributs en lecture seule, utilisés pour HttpResponse.
attr_reader :httpVersion
attr_reader :fields
# Constructeur à l'appel de HttpRequest.new
# host : String : nom de domaine auquel envoyer
# [uri] : String : optionnel : url sans le nom de domaine, par défaut "/"
# [method] : Entier positif : optionnel : méthode de la requête,
# utiliser les constantes de méthodes, par défaut GET
# [port] : Entier positif : optionnel : port sur lequel envoyer, par défaut 80.
def initialize(host,uri = "/",method = GET,port = 80)
@host = host
@uri = uri
@method = method
@port = port
@httpVersion = [1,0]
@fields = {}
@posts = {}
end
# Change la version de http. Major représente le premier numéro, minor le second. (1,0) pour 1.0
# par défaut 1.0
# major : Entier positif : premier numéro de la version
# minor : Entier positif : second numéro de la version
def setHttpVersion(major,minor)
@httpVersion = [major,minor]
end
# Ajoute un header à la requête.
# name : String : nom du header
# value : String : nom de la valeur
def addHeader(name,value)
@fields[name] = value
end
# Ajoute une variable post, n'est utile que dans une méthode POST
# Précondition : name ne doit contenir que des chiffres, lettres non accentuées, "_" et "-"
# name : String : nom de la variable
# value : String : valeur de la variable
def addVarPost(name,value)
@posts[name] = value
end
# Encode les variables post, utilisé par getBody
def urlEncode str
return str.gsub(/([^a-z0-9])/i){|c|
if c == ' ' then
'+'
else
code = c.unpack('C')[0].to_s(16)
if code.length < 2 then
code = '0' + code
end
'%' + code
end
}
end
# Utilisé par HttpResponse.
def getBody()
str = ""
for var in @posts
str += "&" + var[0].to_s + "=" + urlEncode(var[1])
end
return str.slice(1,str.length)
end
end |
Ajoutez le script suivant, juste après, toujours avant le Main, nommez le HttpResponse, et copiez y le code suivant :
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
| # HttpResponse : envoie une requête http en fonction de la requête,
# classe représentant la réponse http.
# Prérequis d'utilisation : il faut avoir dans le dossier racine de son projet
# les fichiers suivants : rgssnetwork.dll, sfml-network-2.dll, sfml-system-2.dll
# Il faut aussi importer la classe HttpRequest.
# Crédits :
# Développement de la bibliothèque C++ : SFML ( [url=http://www.sfml-dev.org/]http://www.sfml-dev.org/[/url] )
# Intégration dans une DLL compatible avec RGSS : Otruch
class HttpResponse
# Constantes de status de la réponse, je ne vais pas toutes les énumérer,
# référez vous à la doc de http.
OK = 200
CREATED = 201
ACCEPTED = 202
NO_CONTENT = 204
RESET_CONTENT = 205
PARTIAL_CONTENT = 206
MULTIPLE_CHOICES = 300
MOVED_PERMANENTLY = 301
MOVED_TEMPORARILY = 302
NOT_MODIFIED = 304
BAD_REQUEST = 400
UNAUTHORIZED = 401
FORBIDEN = 403
NOT_FOUND = 404
RANGE_NOT_SATISFIABLE = 407
INTERNAL_SERVER_ERROR = 500
NOT_IMPLEMENTED = 501
BAD_GATEWAY = 502
SERVICE_NOT_AVAILABLE = 503
GATEWAY_TIMEOUT = 504
VERSION_NOT_SUPPORTED = 505
INVALID_RESPONSE = 1000
CONNECTION_FAILED = 1001
# Importation des fonctions de la DLL, à ne pas utiliser manuellement.
@@new = Win32API.new("rgssnetwork","RGSSNetworkHttpAdd",["P","P","I","I","P","I","I"],"I")
@@addRequestHeader = Win32API.new("rgssnetwork","RGSSNetworkHttpAddRequestHeader",["I","P","P"],"V")
@@sendRequest = Win32API.new("rgssnetwork","RGSSNetworkHttpSendRequest",["I"],"V")
@@getHeader = Win32API.new("rgssnetwork","RGSSNetworkHttpGetResponseHeader",["I","P"],"P")
@@getStatus = Win32API.new("rgssnetwork","RGSSNetworkHttpGetResponseStatus",["I"],"I")
@@getMajorVersion = Win32API.new("rgssnetwork","RGSSNetworkHttpGetResponseMajorVersion",["I"],"I")
@@getMinorVersion = Win32API.new("rgssnetwork","RGSSNetworkHttpGetResponseMinorVersion",["I"],"I")
@@getBody = Win32API.new("rgssnetwork","RGSSNetworkHttpGetBody",["I"],"P")
@@delete = Win32API.new("rgssnetwork","RGSSNetworkHttpDelete",["I"],"V")
# Constructeur à l'appel de HttpResponse.new
# Fait une requête HTTP en fonction de la requête, et stocket le résultat.
# request : HttpRequest : requête à envoyer.
def initialize(request)
@id = @@new.Call(request.host,request.uri,request.method,request.port,request.getBody(),request.httpVersion[0],request.httpVersion[1])
for header in request.fields
@@addRequestHeader.Call(@id,header[0].to_s,header[1])
end
@@sendRequest.Call(@id)
end
# Donne la valeur du header donné en paramètre
# retourne "" si le header n'est pas trouvé
#name : String : nom du header
# return : String : valeur du header.
def getHeader(name)
return @@getHeader.Call(@id,name)
end
# Donne le status de la requête
# vous pouvez soit tester avec des entiers si vous êtes à l'aise
# soit utiliser les constantes de status.
# return : Entier positif : Valeur du status.
def getStatus()
return @@getStatus.Call(@id)
end
# Donne la version HTTP sous forme d'Array.
# return : Array : [major,minor]
# major : Entier positif : premier chiffre de la version (1 pour 1.0)
# minor : Entier positif : second chiffre de la version (0 pour 1.0)
def getHttpVersion()
array = []
array[0] = @@getMajorVersion.Call(@id)
array[1] = @@getMinorVersion.Call(@id)
return array
end
# Donne la version HTTP sous forme de String
# return : String : version HTTP de la réponse.
def getHttpVersionStr()
return @@getMajorVersion.Call(@id).to_s + @@getMinorVersion.Call(@id).to_s
end
# Donne le corps de la requête, c'est ici que vous trouverez le html par exemple.
# return : String : corps de la requête.
def getBody()
return @@getBody.Call(@id)
end
# Destructeur de la socket,
# à utiliser impérativement lorsque vous n'en avez plus besoin !
def destroy()
@@delete.Call(@id)
end
end |
Manuel d'utilisation :
Une requête HTTP se fait en 2 parties : on crée la requête, on l'envoie au serveur, une réponse est créée, on la lit. Là j'ai fais les choses plus simplement, on crée la requête, on crée la réponse en y mettant la requête, l'envoie se fait automatiquement, on lit la réponse.
Etape 1, création de la requête via HTTPRequest :
Différentes constantes sont là pour le type de la méthode à envoyer :
HttpRequest::GET : demande la page par url
HttpRequest::POST : demande la page par url et y transmet des variables
HttpRequest::HEAD
HttpRequest::PUT
HttpRequest::DELETE
Si vous utilisez les méthodes HEAD, PUT et DELETE, c'est que vous les connaissez, moi perso je ne les connais pas, j'utilise que GET et POST.
Création de la requête :
On appelle le constructeur, on passe en argument :
host : String : le nom de domaine, peut être "localhost" (exemple "google.fr" )
uri : optionnel : String : le chemin par rapport à la racine, autrement dit ce qu'il y a après le nom de domaine dans l'url, par défaut "/"
method : optionnel : méthode de la requête, utilisez les constantes de méthode, par défaut GET
port : optionnel : entier positif : c'est le port où envoyer la requête, par défaut 80, c'est le port où écoute tous les serveurs web.
exemple : request = HttpRequest.new("localhost","/trophee.php",HttpRequest::POST)
Ces 4 attributs sont publics, on peut y accéder en écriture et en lecture, pour les changer et les lire, exemple :
request.host = "google.fr"
Cela permet par exemple, si on veut juste changer la méthode mais pas l'uri, de faire :
request = HttpRequest.new("localhost")
request.method = HttpRequest::POST
On peut changer la version de HTTP en appelant la méthode setHttpVersion et y indiquant le premier numéro et le second numéro, en entier,
pour la version "1.0" c'est request.setHttpVersion(1,0)
C'est à titre d'exemple, par défaut, la version est "1.0"
On peut ajouter/changer le header de la requête via la méthode addHeader. Le premier argument est le nom de l'header, le second est la valeur.
exemple :
request.addHeader("Content-Type", "application/x-www-form-urlencoded")
Pour une méthode post, on peut ajouter des variables via la méthode addVarPost, ayant le nom de la variable et sa valeur en argument.
Le nom de la variable ne doit contenir que des lettres non accentuées, chiffres, "-" et "_".
Il y a une méthode publique et des attributs en lecture seule, n'y touchez pas, elle sert d'utilitaire pour la classe HttpResponse.
Lire la réponse :
Beaucoup de constantes ont été créées pour le statut de la requête, en général on se sert des chiffres, mais il est toujours bien de pouvoir utiliser certaines constantes, à vous de voir.
Les constantes sont :
HttpResponse::OK = 200
HttpResponse::CREATED = 201
HttpResponse::ACCEPTED = 202
HttpResponse::NO_CONTENT = 204
HttpResponse::RESET_CONTENT = 205
HttpResponse::PARTIAL_CONTENT = 206
HttpResponse::MULTIPLE_CHOICES = 300
HttpResponse::MOVED_PERMANENTLY = 301
HttpResponse::MOVED_TEMPORARILY = 302
HttpResponse::NOT_MODIFIED = 304
HttpResponse::BAD_REQUEST = 400
HttpResponse::UNAUTHORIZED = 401
HttpResponse::FORBIDEN = 403
HttpResponse::NOT_FOUND = 404
HttpResponse::RANGE_NOT_SATISFIABLE = 407
HttpResponse::INTERNAL_SERVER_ERROR = 500
HttpResponse::NOT_IMPLEMENTED = 501
HttpResponse::BAD_GATEWAY = 502
HttpResponse::SERVICE_NOT_AVAILABLE = 503
HttpResponse::GATEWAY_TIMEOUT = 504
HttpResponse::VERSION_NOT_SUPPORTED = 505
HttpResponse::INVALID_RESPONSE = 1000
HttpResponse::CONNECTION_FAILED = 1001
On initialise la réponse grâce à la requête, la requête est directement envoyée.
response = HttpResponse.new(request)
Attention, il est IMPERATIF d'utiliser la méthode destroy quand on n'a plus besoin de la reponse.
response.destroy
On lit le statut de la requête via la méthode getStatus
status = response.getStatus
Pour avoir la valeur d'un header, c'est la méthode getHeader avec pour paramètre, le nom du header
exemple : contentType = response.getHeader("Content-Type")
On peut avoir la version http de la réponse de deux manières :
dans un array via la méthode getHttpVersion , le premier élément est le premier chiffre, le second est le deuxième chiffre (pour "1.0" on a [1,0] )
version = response.getHttpVersion
if version[0] == 1 then
#...
ou dans un String via la méthode getHttpVersionStr
version = response.getHttpVersionStr
Et enfin, ce que vous attendez tous, le contenu de la réponse ! On peut y voir par exemple le html, ou le contenu d'une image, ou un simple "coucou" fait avec un echo en php. On y accède via la méthode getBody .
contenu = response.getBody
Mis à jour le 22 mai 2021.
|