Caching proxy server is a good example of language/standard library capabilities as it uses both Network IO and concurrency.
This is example is pretty much based on hello world #4 example
using concurrent
using util
using web
using wisp
class ProxyMain : AbstractMain
{
@Opt { help = "http port" }
Int port := 8080
override Int run()
{
proxy := ProxyMod { hostname = port == 80 ? "localhost" : "localhost:$port" }
return runServices([WispService { it.port = this.port; root = proxy}])
}
}
const class CacheElem
{
new make(|This| f) { f(this) }
const Str:Str headers
const Str data
}
const class ProxyMod : WebMod
{
const Str hostname
new make(|This| f) { f(this) }
const Actor actor := Actor(ActorPool()) |uri| {
if (Actor.locals["proxy::cache"] == null)
Actor.locals["proxy::cache"] = Uri:CacheElem[:]
Uri:CacheElem map := Actor.locals["proxy::cache"]
if (map[uri] != null)
return map[uri]
client := WebClient(uri)
stream := client.getIn
stream.charset=Charset("ISO-8859-1")
map[uri] = CacheElem {
headers = client.resHeaders
data = stream.readAllStr(false)
}
client.close
return map[uri]
}
override Void onGet()
{
if (req.headers["Host"] == hostname)
{
res.headers["Content-Type"] = "text/plain; charset=utf-8"
res.out.print("Nothing here")
return
}
CacheElem? elem := actor.send(req.absUri).get
res.headers.setAll(elem.headers)
buf := Buf()
buf.charset = Charset("ISO-8859-1")
buf.print(elem.data)
buf.flip
res.out.writeBuf(buf)
}
}
Well, this solution seems somewhat bloated to my taste:
I use ISO-8859-1 because a) I know it is; b) It doesn't crash on .png files.
Creating Buf in last lines of onGet may seem unnecessary if you think that res.out.charset will do anything.
All charset magic is used because I don't have immutable Buf.
Of (2): As far as I get res.out is an instance of WebOutStream which is wrapper around SysOutStream, therefore changing charset in res.out does nothing. I think it would be nice to add such delegation to OutStream.
Of (3): I can store content as Str or Int[] (or something I didn't come up with). Plus side of Int[] - no charsets. Minus side - reading/writing by one byte (even more bloated, set aside performance). Buf-like immutable entity surely would help.
ivanMon 30 Aug 2010
vkuzkokov,
Nice idea! Few times I needed a simple proxy for testing but was too lazy to find and configure something. So having customizable pure fan proxy can be very useful sometimes.
vkuzkokov Sun 29 Aug 2010
Caching proxy server is a good example of language/standard library capabilities as it uses both Network IO and concurrency.
This is example is pretty much based on
hello world #4
exampleWell, this solution seems somewhat bloated to my taste:
onGet
may seem unnecessary if you think thatres.out.charset
will do anything.Buf
.Of (2): As far as I get
res.out
is an instance ofWebOutStream
which is wrapper aroundSysOutStream
, therefore changingcharset
inres.out
does nothing. I think it would be nice to add such delegation toOutStream
.Of (3): I can store content as
Str
orInt[]
(or something I didn't come up with). Plus side ofInt[]
- no charsets. Minus side - reading/writing by one byte (even more bloated, set aside performance). Buf-like immutable entity surely would help.ivan Mon 30 Aug 2010
vkuzkokov,
Nice idea! Few times I needed a simple proxy for testing but was too lazy to find and configure something. So having customizable pure fan proxy can be very useful sometimes.
Few notes on the code:
This is just an idea, haven't tried to compile or launch this code :)