naga is awesome!

28 views
Skip to first unread message

Alexander Botero-Lowry

unread,
Mar 6, 2009, 3:32:41 AM3/6/09
to Naga Users
Hi guys,

Today I started looking for an asynchronous memcache client in Java,
and all I could find was these huge byzantine monstrosities (which is
of course the norm for java libraries), and so I decided that I should
give a go to writing my own using NIO, but when I went to look at how
to use the NIO api I went back to looking for a memcache client :D

After some more exploring down that avenue I went back to the NIO
street ,and I found a few frameworks that seemed to make it more
reasonable but they were all massive, and then I ran into Naga!

I wrote up a little wrapper around naga for Scala to make it a little
more language appropriate, and I've just started to write my little
Memcache library.

I still have a long way to go, and I need to cleanup the apis a bunch
more, but I think I will have a nice, albeit simple wrapper for Scala
when I'm done (and a nice Memcache library).

Thanks for the great project!

++++++ Naga Wrapper for scala and a really horrible and incomplete
client impl ontop of it +++++

object TCPMagic {
sealed trait TCPAction {
val socket: NIOSocket
}

case class ConnectionOpened(socket: NIOSocket) extends TCPAction
case class PacketReceived(socket: NIOSocket, bytes: Array[Byte])
extends TCPAction
case class ConnectionBroken(socket: NIOSocket, exc: Exception)
extends TCPAction

trait TCPMatcher { def match_action(match_on: TCPAction):Unit }

def run(host: String, port: Int, client: TCPMatcher) {
val service = new NIOService();
val sock = service.openSocket(host, port)
sock listen(new SocketObserver() {
def connectionOpened(socket: NIOSocket) {
client.match_action(ConnectionOpened(socket))
}
def packetReceived(socket: NIOSocket, bytes: Array[Byte]) {
client.match_action(PacketReceived(socket, bytes))
}
def connectionBroken(socket: NIOSocket, exc: Exception) {
client.match_action(ConnectionBroken(socket, exc))
}
})
while (true) {
service.selectBlocking();
}
}
}

class MemcacheClient extends TCPMagic.TCPMatcher {
import TCPMagic._

trait MemcacheCommand {
val msg: String
val callback: (Any => Unit)

queue = queue enqueue this
if (sock != null && handling == null) next_command

def handle(data: Array[Byte]) : Unit
}

var sock: NIOSocket = null;
val EOL = "\r\n";
var queue: Queue[MemcacheCommand] = new Queue()
var handling: MemcacheCommand = null;

protected def next_command() {
if (!queue.isEmpty) {
// XXX fulhack, maybe a nicer way to do this
val tpl = queue dequeue
var cmd = tpl._1
queue = tpl._2

handling = cmd
sock.write(cmd.msg.getBytes)
}
}

class GetCommand(msgx: String, callbackx: (Any=>Unit)) extends
MemcacheCommand {
val msg:String = msgx
val callback:(Any => Unit) = callbackx

def handle(data: Array[Byte]) = {
callback(new String(data))
}
}

def get(key: String, callback: (Any => Unit)) {
new GetCommand("get "+key+EOL, callback)
}

def match_action(match_on: TCPAction) {
match_on match {
case PacketReceived(s, b) => {
handling.handle(b)
handling = null
next_command
}
case ConnectionBroken(s, e) => println("Broken")
case ConnectionOpened(s) => {
println("connection")
sock = s;
next_command
}
}
}
}

val mcc = new MemcacheClient()
mcc.get("x", { a => println("OUT "+a) })

TCPMagic.run("127.0.0.1", 11211, mcc)

Christoffer Lernö

unread,
Mar 6, 2009, 7:22:21 AM3/6/09
to naga-...@googlegroups.com
Thanks Alexander,

I'm happy to hear that it has been useful to you.

If you have any suggestions on improvements to the interfaces then I'm
very interested in hearing them.


Sincerely,

Christoffer
Reply all
Reply to author
Forward
0 new messages