HTTP Calls and stuff

BlitzMax Forums/BlitzMax Programming/HTTP Calls and stuff

Grey Alien(Posted 2008) [#1]
OK so I need to open a socket connection and communicate with a server on the Internet through a TCP channel. I think I am supposed to be using HTTP calls, but I don't know much about this. Does that sound right and possible in BMax? Thanks for any info.

Oh and what's JSON? I'm told it’s data encapsulation method. Is it possible to use this with BMax? I guess it just means I format the data in a certain way and then send it like that (and unwrap it when I receive it).


Warpy(Posted 2008) [#2]
Enough threads, Grey Alien? Would you in fact like someone to write your game for you? :P

A quick google will get you to a very good explanation at http://www.json.org/
In fact, that's caughy my interest, I might knock up a little JSON library this afternoon, I've got nothing else going on.

Bmax comes with an HTTPStream module, but a look at the code archives shows leadwerks has fixed it somehow - http://www.blitzbasic.com/codearcs/codearcs.php?code=2267


Brucey(Posted 2008) [#3]
There are a couple of JSON libraries available for BlitzMax already. That forum Search thingme tis quite good.


Grey Alien(Posted 2008) [#4]
The texture size thread is old and someone else resurrected it, so that's only two threads ;-) (well plus one a few days old)

In fact, that's caught my interest, I might knock up a little JSON library this afternoon, I've got nothing else going on.
This sounds cool, please share! :-)

Thanks for the link it may prove useful.


Warpy(Posted 2008) [#5]
But none of them were written by me, Brucey!

The forum search thing isn't quite good enough to search the code archives, which is where they live, though.


Grey Alien(Posted 2008) [#6]
Yeah I normally use google and tag on BlitzMax. I just thought I'd ask first whether what I'm asking makes sense and is even possible, sounds like it is right?


Warpy(Posted 2008) [#7]
Crumbs! I've written my parser and, in a world first for WarpyCode(tm), it worked first time! Seriously, the very first time I ran it it parsed an example from the json.org site!

Type jsondecoder
	Field txt$
	Field i
	Field curchr$
	Field things:TList
	
	Method New()
		things=New TList
	End Method

	Method getnext(tokens$[],onlywhitespace=1)
		oldi=i
		While i<Len(txt)
			c$=Chr(txt[i])
			i:+1
			For token$=EachIn tokens
				If c=token 
					curchr=c
					Return 1
				EndIf
			Next
			If onlywhitespace And (Not (c=" " Or c="~t" Or c="~n" Or c="~r"))
				i:-1
				Return 0
			EndIf
		Wend
		i=oldi
		Return 0
	End Method
	
	Function Create:jsondecoder(txt$)
		j:jsondecoder=New jsondecoder
		j.txt=txt
		j.i=i
		Return j
	End Function
	
	Method parse()
		While getnext(["{","["])
			Select curchr
			Case "{" 'new object
				o:jsonobject=parseobject()
				If Not o
					Print "error - couldn't parse object"
				EndIf
				things.addlast o
			Case "[" 'new array
				a:jsonarray=parsearray()
				If Not a
					Print "error - couldn't parse array"
				EndIf
				things.addlast a
			End Select
		Wend
	End Method	
	
	Method parseobject:jsonobject()
		o:jsonobject=New jsonobject
		While getnext(["~q","}"])
			Select curchr
			Case "~q"
				p:jsonpair=parsepair()
				If Not p
					Print "error reading pair"
				EndIf
				o.pairs.addlast p
				If Not getnext([",","}"])
					Print "error after reading pair - expected either , or }"
				EndIf
				If curchr="}"
					Return o
				EndIf
			Case "}"
				Return o
			End Select
		Wend
		
		Print "error reading Object - expected a } at least!"
	End Method
	
	Method parsepair:jsonpair()
		p:jsonpair=New jsonpair
		p.name=parsestring()
		If Not getnext([":"])
			Print "error reading pair - expected a :"
		EndIf
		v:jsonvalue=parsevalue()
		If Not v
			Print "error reading pair - couldn't read a value"
		EndIf
		p.value=v
		Return p
	End Method
	
	Method parsearray:jsonarray()
		a:jsonarray=New jsonarray
		While getnext(["~q","-","0","1","2","3","4","5","6","7","8","9","{","[","t","f","n","]"])
			Select curchr
			Case "~q","-","0","1","2","3","4","5","6","7","8","9","{","[","t","f","n"
				i:-1
				v:jsonvalue=parsevalue()
				a.values.addlast v
				If Not getnext([",","]"])
					Print "error - expecting , or ]"
				EndIf
				If curchr="]"
					Return a
				EndIf
				
			Case "]"
				Return a
			End Select
		Wend
		Print "error - expecting a value or ]"
	End Method
	
	Method parsestring$()
		oldi=i
		s$=""
		While getnext(["~q","\"],0)
			s:+txt[oldi..i-1]
			Select curchr
			Case "~q"
				Return s
			Case "\"
				Select Chr(txt[i])
				Case "~q"
					s:+"~q"
				Case "\"
					s:+"\"
				Case "/"
					s:+"/"
				Case "b"
					s:+Chr(8)
				Case "f"
					s:+Chr(12)
				Case "n"
					s:+"~n"
				Case "r"
					s:+"~r"
				Case "t"
					s:+"~t"
				Case "u"
					s:+parseunicode()
				End Select
				i:+1
			End Select
		Wend
	End Method
	
	Method parseunicode$()
		n:Short=0
		For t=1 To 4
			n:*16
			c=txt[i+t]
			If c>48 And c<57
				n:+c-48
			ElseIf c>=65 And c<=70
				n:+c-55
			ElseIf c>=97 And c<=102
				n:+c-87
			EndIf
		Next
		i:+4
		Return Chr(n)
	End Method
	
	Method parsevalue:jsonvalue()
		If Not getnext(["~q","-","0","1","2","3","4","5","6","7","8","9","{","[","t","f","n"])
			Print "error - expecting the beginning of a value"
		EndIf
		Select curchr
		Case "~q"
			s$=parsestring()
			Return jsonstringvalue.Create(s)
		Case "-","0","1","2","3","4","5","6","7","8","9"
			n:Double=parsenumber()
			Return jsonnumbervalue.Create(n)
		Case "{"
			o:jsonobject=parseobject()
			Return o
		Case "["
			a:jsonarray=parsearray()
			Return a
		Case "t"
			i:+3
			Return jsonliteralvalue.Create(1)
		Case "f"
			i:+4
			Return jsonliteralvalue.Create(0)
		Case "n"
			i:+2
			Return jsonliteralvalue.Create(-1)
		End Select
	End Method
	
	Method parsenumber:Double()
		i:-1
		sign=1
		n:Double=0
		Select Chr(txt[i])
		Case "-"
			i:+2
			Return parsenumber()*(-1)
		Case "0"
			i:+1
			If getnext(["."])
				n=parsefraction()
			EndIf
		Case "1","2","3","4","5","6","7","8","9"
			n=parseinteger()
			If getnext(["."])
				n:+parsefraction()
			EndIf
		End Select
		
		If Chr(txt[i])="e" Or Chr(txt[i])="E"
			i:+1
			Select Chr(txt[i])
			Case "+"
				sign=1
			Case "-"
				sign=-1
			Default
				Print "error - not a + or - when reading exponent in number"
			End Select
			e=parseinteger()
			n:*10^(sign*e)
		EndIf
		Return n
	End Method
			
	Method parsefraction:Double()
		digits=1
		n:Double=0
		While txt[i]>=48 And txt[i]<=57 And i<Len(txt)
			n:*10
			n:+txt[i]-48
			i:+1
			digits:+1
		Wend
		n:/digits
		If i=Len(txt)
			Print "error - reached EOF while reading number"
		EndIf
		Return n
	End Method
	
	Method parseinteger:Double()
		n:Double=0
		While txt[i]>=48 And txt[i]<=57 And i<Len(txt)
			n:*10
			n:+txt[i]-48
			i:+1
		Wend
		If i=Len(txt)
			Print "error - reached EOF while reading number"
		EndIf
		Return n
	End Method
			
End Type

Type jsonvalue

	Method repr$()
		Return ""
	End Method
End Type

Type jsonobject Extends jsonvalue
	Field pairs:TList

	Method New()
		pairs=New TList
	End Method
	
	Method repr$()
		t$="{ "
		op:jsonpair=Null
		For p:jsonpair=EachIn pairs
			If op Then t:+" , "
			t:+p.repr()
			op=p
		Next
		t:+" }"
		Return t
	End Method
	
End Type

Type jsonpair
	Field name$,value:jsonvalue

	Method repr$()
		Return "~q"+name+"~q : "+value.repr()
	End Method
End Type

Type jsonarray Extends jsonvalue
	Field values:TList
	
	Method New()
		values=New TList
	End Method
	
	Method repr$()
		t$="[ "
		ov:jsonvalue=Null
		For v:jsonvalue=EachIn values
			If ov Then t:+" , "
			t:+v.repr()
			ov=v
		Next
		t:+" ]"
		Return t
	End Method
End Type


Type jsonstringvalue Extends jsonvalue
	Field txt$
	
	Function Create:jsonstringvalue(txt$)
		jsv:jsonstringvalue=New jsonstringvalue
		jsv.txt=txt
		Return jsv
	End Function
	
	Method repr$()
		Return "~q"+txt+"~q"
	End Method
End Type

Type jsonnumbervalue Extends jsonvalue
	Field number:Double
	
	Function Create:jsonnumbervalue(n:Double)
		jnv:jsonnumbervalue=New jsonnumbervalue
		jnv.number=n
		Return jnv
	End Function
	
	Method repr$()
		Return String(number)
	End Method
End Type

Type jsonliteralvalue Extends jsonvalue
	Field value
	'1 - true
	'0 - false
	'-1 - nil
	
	Function Create:jsonliteralvalue(value)
		jlv:jsonliteralvalue=New jsonliteralvalue
		jlv.value=value
		Return jlv
	End Function
	
	Method repr$()
		Select value
		Case 1
			Return "true"
		Case 0
			Return "false"
		Case -1
			Return "nil"
		End Select
	End Method
End Type



'EXAMPLE
f:TStream=ReadFile("json.txt")
txt$=""
While Not Eof(f)
	txt:+f.ReadLine()
Wend

j:jsondecoder=jsondecoder.Create(txt)
j.parse()


For v:jsonvalue=EachIn j.things
	Print v.repr()
Next


This is UNPRECEDENTED. I need to go and lie down now.


Grey Alien(Posted 2008) [#8]
Wow that was incredibly quick! I might be testing this out soon with my project if it all goes to plan. Many thanks!


Warpy(Posted 2008) [#9]
De nada.

Actually, not de nada. I'd appreciate a copy of whatever this is going into when it's finished ;)


Grey Alien(Posted 2008) [#10]
I'll see what I can do. I can probably get you a runtime exe, but definitely not the source code, sorry.

In the event that I forget, remind me when I release my next game.


Warpy(Posted 2008) [#11]
I'm not puki, just an exe will be fine!
Ta very much like.


AlexO(Posted 2008) [#12]
Brucey's LibCurlModule module for blitzmax makes it easy to talk to web servers using HTTP.


Grey Alien(Posted 2008) [#13]
OK thanks AlexO. I'll check it out. I'm a noob in this sort of area, but I'm sure I can learn.


Grey Alien(Posted 2008) [#14]
@Warpy: Just been testing your code. Good job. Why does it get integers and turn them into doubles? I guess it doesn't matter but it might be handy if it stored them as ints so they could be reproduced (printed or turned into strings) as ints, but maybe that's the job of the code that interprets the parsed data...