diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..9dc886a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+
+
+
+all: clean
+ cd lib; make install
+ cd main; make install
+
+
+clean:
+ cd lib; make clean
+ cd main; make clean
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644
index 0000000..8c93e85
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,10 @@
+include $(GOROOT)/src/Make.$(GOARCH)
+
+TARG=malus
+GOFILES=callmanager.go\
+ udp.go\
+ utility.go\
+ webinterface.go\
+ sleepqueue.go
+
+include $(GOROOT)/src/Make.pkg
diff --git a/lib/callmanager.go b/lib/callmanager.go
new file mode 100644
index 0000000..a47790a
--- /dev/null
+++ b/lib/callmanager.go
@@ -0,0 +1,660 @@
+package malus
+
+
+// TODO: taipei torrent makes []byte of "adequate" size when reading a
+// string. it does not check if the bencoded string is really that
+// long -> hilarious DOS
+
+import (
+ "fmt"
+ "os"
+ "bytes"
+ "encoding/hex"
+ "jackpal/bencode"
+ "reflect"
+ "net"
+ "time"
+ "log"
+ "rand"
+)
+
+const (
+ HASHLEN = 20
+ IDLEN = 8
+ TIMEOUT = 1500 * 1000 * 1000
+)
+
+
+type DummyWriter struct{}
+
+func (d *DummyWriter) Write(p []byte) (n int, err os.Error) {
+ return len(p), nil
+}
+
+
+type Transceiver interface {
+ SendRPC(rpc *RPC) (err os.Error)
+ GetReceiveChannel() <-chan *Packet
+}
+
+
+type Header struct {
+ Version uint8
+ Sender string
+ Id uint64
+ DHTId []byte
+ Call uint8
+ PayloadLength uint16
+ Payload *Payload
+}
+
+func (h *Header) String() string {
+ b := bytes.NewBufferString("")
+
+ if h == nil { return "<*Header: nil>" }
+
+ b.WriteString("Header {\n")
+
+ b.WriteString(fmt.Sprintf(" % -8s = %x\n",
+ "Sender",
+ h.Sender))
+
+ b.WriteString(fmt.Sprintf(" % -8s = 0x%016x\n",
+ "Id",
+ h.Id))
+
+ b.WriteString(fmt.Sprintf(" % -8s = 0x%02x\n", "Call", h.Call))
+
+ b.WriteString(fmt.Sprintf(" % -8s = 0x%04x\n", "PLength", h.PayloadLength))
+
+ b.WriteString(fmt.Sprintf(" % -8s = %s\n",
+ "DHTId",
+ hex.EncodeToString(h.DHTId)))
+
+ b.WriteString(fmt.Sprintf(" % -8s = 0x%02x\n", "Version", h.Version))
+
+ b.WriteString("}")
+
+ return b.String()
+}
+
+type Payload struct{}
+
+
+type MalusDecodingError string
+
+func (s MalusDecodingError) String() string { return string(s) }
+
+type RPCError string
+
+func (s RPCError) String() string { return string(s) }
+
+
+type rpcentry struct {
+ fun *reflect.FuncValue
+ funtype *reflect.FuncType
+ strictmatch bool
+}
+
+
+type RPCFrame struct {
+ Name string
+ Args []reflect.Value
+ OutArgs []interface{}
+}
+
+type RPC struct {
+ Header *Header
+ RPCFrame *RPCFrame
+ Payload interface{}
+ Packet *Packet
+}
+
+
+type RunningRPC struct {
+ rpc *RPC
+ retchan chan *RPC
+}
+
+type Packet struct {
+ To net.Addr
+ From net.Addr
+ Data []byte
+}
+
+
+type CallManager struct {
+ Id string
+ rpcmap map[string](*rpcentry)
+ transceiver Transceiver
+ logger *log.Logger
+ log bool
+ running map[uint64]*RunningRPC
+ regchan chan *RunningRPC
+ inchan chan *RPC
+ timeout int64
+}
+
+
+func NewCallManager(transceiver Transceiver) *CallManager {
+ cm := new(CallManager)
+
+ cm.rpcmap = make(map[string](*rpcentry), 8)
+ cm.transceiver = transceiver
+ cm.logger = log.New(os.Stdout, nil, "CallManager: ", 0)
+ cm.log = true
+ cm.running = make(map[uint64]*RunningRPC)
+ cm.regchan = make(chan *RunningRPC)
+ cm.inchan = make(chan *RPC)
+ cm.timeout = TIMEOUT
+
+ return cm
+}
+
+
+func (cm *CallManager) manageRunning() {
+ running := cm.running
+
+ timeout := make(chan uint64)
+
+ for {
+ select {
+ case r := <-cm.regchan:
+ running[r.rpc.Header.Id] = r
+ // TODO: manage with queue
+ go func(id uint64){
+ // TODO: check EINTR
+ time.Sleep(cm.timeout)
+ timeout <- id
+
+ }(r.rpc.Header.Id)
+ case rpc := <-cm.inchan:
+ Id := rpc.Header.Id
+ if runningrpc, ok := running[Id]; ok {
+ runningrpc.retchan <- rpc
+ running[Id] = nil, false
+ }
+ case id := <- timeout:
+ if runningrpc, ok := running[id]; ok {
+ runningrpc.retchan <- nil
+ running[id] = nil, false
+ }
+ }
+ }
+}
+
+func (cm *CallManager) constructAnswer(req *RPC, retcall uint8, retis []interface{}) (retrpc *RPC) {
+ retrpc = new(RPC)
+
+ header := new(Header)
+ retrpc.Header = header
+ header.Call = retcall
+ header.Id = req.Header.Id
+ header.DHTId = req.Header.DHTId
+ header.Sender = cm.Id
+ header.Version = req.Header.Version
+
+ retrpc.Payload = retis
+
+ retrpc.Packet = new(Packet)
+ retrpc.Packet.To = req.Packet.From
+
+ return
+}
+
+// TODO: errors...
+func (cm *CallManager) DispatchRPC(rpc *RPC) {
+ switch rpc.Header.Call {
+ case 0x01:
+ retcall, retis, err := cm.DispatchRequest(rpc)
+ if err == nil {
+ retrpc := cm.constructAnswer(rpc, retcall, retis)
+ packet := cm.EncodeRPC(retrpc)
+ if packet == nil {
+ panic("packet could not be encoded?!")
+ }
+ retrpc.Packet.Data = packet
+ cm.transceiver.SendRPC(retrpc)
+ }
+ case 0x81, 0x82, 0x83:
+ cm.DispatchAnswer(rpc)
+ default:
+ return
+ }
+
+}
+
+
+func (cm *CallManager) DispatchRequest(rpc *RPC) (retcall uint8, retis []interface{}, err os.Error) {
+ err = nil
+ retcall = 0x83
+ retis = make([]interface{}, 0)
+
+ rpcdesc, ok := cm.rpcmap[rpc.RPCFrame.Name]
+ if !ok {
+ if cm.log {
+ cm.logger.Logf("rpc %q not found!\n", rpc.RPCFrame.Name)
+ }
+ retcall = 0x82
+ return
+ }
+
+ args := rpc.RPCFrame.Args
+ funtype := rpcdesc.funtype
+
+ if len(args) != funtype.NumIn() {
+ err = MalusDecodingError("num args do not match")
+ return
+ }
+
+ // always strict matching!
+ for i := 0; i < len(args); i++ {
+ //fmt.Printf("checking type %d ", i)
+ ta := reflect.Typeof(args[i].Interface())
+ tb := funtype.In(i)
+ //fmt.Printf("arg %d ta %v tb %v\n", i, ta, tb)
+ if !(ta == tb) {
+ if cm.log {
+ cm.logger.Logf("type %d does not match!\n", i)
+ }
+ err = MalusDecodingError("types not matching")
+ return
+ }
+ }
+
+ rets := rpcdesc.fun.Call(args)
+ retis = make([]interface{}, len(rets))
+ for i, val := range rets {
+ retis[i] = val.Interface()
+ }
+
+ retcall = 0x81
+
+ return
+}
+
+
+func (cm *CallManager) DispatchAnswer(rpc *RPC) {
+ //cm.logger.Logf("%v", rpc)
+ cm.inchan <- rpc
+}
+
+
+func (cm *CallManager) AddRPC(name string, fun interface{}) {
+
+ fwrapper, ok := reflect.NewValue(fun).(*reflect.FuncValue)
+ if !ok {
+ panic("you did not pass a function to *CallManager.AddRPC")
+ }
+
+ entry := new(rpcentry)
+ entry.fun = fwrapper
+ entry.funtype = reflect.Typeof(fun).(*reflect.FuncType)
+ entry.strictmatch = true
+
+ cm.rpcmap[name] = entry
+
+}
+
+func (c *CallManager) ParseHeader(raw []byte) (header *Header, payloadpos int, err os.Error) {
+
+ l := len(raw)
+ if l < 1 {
+ return nil, 0, MalusDecodingError("header too short")
+ }
+
+ header = new(Header)
+
+ header.Version = raw[0]
+
+ if header.Version == 1 {
+ if l < 32 {
+ return nil, 0, MalusDecodingError("invalid header length for type 1 header")
+ }
+
+ header.Sender = string(raw[1 : 1+20])
+ //copy(header.Id[0:8], raw[21:21+8])
+ header.Id = 0
+ for i := 0; i < 8; i++ {
+ header.Id <<= 8
+ header.Id |= uint64(raw[21+i])
+ }
+ // TODO: nil or {} ?
+ header.DHTId = nil
+
+ header.Call = raw[29]
+
+ // payload length is in network byte order
+ header.PayloadLength = uint16(raw[30]<<8) | uint16(raw[31])
+
+ return header, 32, nil
+ } else {
+ return nil, 1, MalusDecodingError("unknown header version")
+ }
+
+ return nil, 0, MalusDecodingError("invalid flow")
+}
+
+
+func (c *CallManager) DecodePayload(h *Header, raw []byte, payloadpos int) (payload interface{}, err os.Error) {
+
+ if h.Call != 0x01 && (h.Call < 0x81 || h.Call > 0x83) {
+ return nil, MalusDecodingError("unkown call")
+ }
+
+ if (h.Call > 0x83 || h.Call < 0x82) && payloadpos == len(raw) {
+ return nil, MalusDecodingError("no payload!")
+ } else if (h.Call <= 0x83 || h.Call >= 0x82) && payloadpos == len(raw) {
+ return make(map[string]interface{}), nil
+ }
+ payloadbuf := bytes.NewBuffer(raw[payloadpos:])
+
+ data, err := bencode.Decode(payloadbuf)
+ if err != nil {
+ return nil, MalusDecodingError("bencoding error")
+ }
+
+ //fmt.Printf("decode ok data %v\n", data)
+ return data, nil
+}
+
+
+func (c *CallManager) ReadRPC(h *Header, payload interface{}) (rpcframe *RPCFrame, err os.Error) {
+
+ rpcframe = nil
+
+ if h.Call == 0x01 {
+ switch payload.(type) {
+ default:
+ err = MalusDecodingError("not a map!\n")
+ return
+ case map[string]interface{}:
+
+ }
+ } else if h.Call == 0x81 {
+ if _, ok := payload.([]interface{}); !ok {
+ err = MalusDecodingError("retvals not list")
+ return
+ }
+ rpcframe = nil
+ err = nil
+ return
+ }
+
+ rpcdesc := payload.(map[string]interface{})
+ irpcname, ok := rpcdesc["name"]
+ if !ok {
+ err = MalusDecodingError("name not given")
+ return
+ }
+
+ rpcname, ok := irpcname.(string)
+ if !ok {
+ err = MalusDecodingError("name not a string")
+ return
+ }
+
+ arglist, ok := rpcdesc["args"]
+ if !ok {
+ fmt.Printf("args not given\n")
+ return
+ }
+
+ switch arglist.(type) {
+ default:
+ err = MalusDecodingError("arglist not a slice\n")
+ return
+ case []interface{}:
+
+ }
+
+ argslice := reflect.NewValue(arglist).(*reflect.SliceValue)
+ //fmt.Printf("=>\n")
+ sl := argslice.Len()
+ rpcframe = new(RPCFrame)
+ rpcframe.Name = rpcname
+ // Args[0] is RPC info
+ rpcframe.Args = make([]reflect.Value, sl+1)
+ for i := 0; i < sl; i++ {
+ elem := argslice.Elem(i)
+
+ value := elem.(*reflect.InterfaceValue).Elem()
+ rpcframe.Args[i+1] = value
+
+ //fmt.Printf(" elem %d is type %s\n", i, reflect.Typeof(value).String())
+
+ }
+ //fmt.Printf("<=\n")
+
+
+ err = nil
+ return
+
+}
+
+
+func (cm *CallManager) EncodeRPC(rpc *RPC) []byte {
+ epayload := cm.EncodePayload(rpc)
+ plen := len(epayload)
+ // maximum for payload size in header
+ if plen >= (1 << 16) {
+ panic("EncodeRPC: payload too long")
+ }
+ rpc.Header.PayloadLength = uint16(plen)
+ //fmt.Printf("plen %d\n", plen)
+
+ eheader := cm.EncodeHeader(rpc)
+ if eheader == nil {
+ panic("EncodeRPC: could not encode outgoing header!")
+ }
+ hlen := len(eheader)
+ //fmt.Printf("hlen %d\n", hlen)
+
+ packet := make([]byte, plen+hlen)
+ copy(packet[0:hlen], eheader)
+ copy(packet[hlen:hlen+plen], epayload)
+
+ return packet
+}
+
+
+func (cm *CallManager) EncodeHeader(rpc *RPC) []byte {
+ header := rpc.Header
+ buf := bytes.NewBuffer(nil)
+
+ buf.WriteByte(header.Version)
+
+ switch header.Version {
+ case 1:
+ if len(header.Sender) != HASHLEN {
+ panic("invalid sender, cannot encode header")
+ }
+ buf.WriteString(header.Sender)
+
+ t := header.Id
+ // MSB first
+ for i := 0; i < 8; i++ {
+ buf.WriteByte(byte(t >> 56))
+ t <<= 8
+ }
+
+ buf.WriteByte(header.Call)
+
+ buf.WriteByte(byte(header.PayloadLength >> 8))
+ buf.WriteByte(byte(header.PayloadLength & 0xFF))
+ default:
+ return nil
+ }
+
+ return buf.Bytes()
+
+}
+
+
+// TODO: this is a misnomer...
+func (cm *CallManager) EncodePayload(rpc *RPC) []byte {
+ buf := bytes.NewBuffer(nil)
+
+ //cm.logger.Logf("encoding payload of call %d\n", rpc.Header.Call)
+
+ bencode.Marshal(buf, rpc.Payload)
+ b := buf.Bytes()
+ /*if len(b) == 0 {
+ b = make([]byte, 2)
+ b[0] = 'l'
+ b[1] = 'e'
+ }*/
+ return b
+}
+
+
+func (cm *CallManager) DispatchPacket(packet *Packet) {
+ rpc := new(RPC)
+ rpc.Packet = packet
+ bts := packet.Data
+
+ var t1, t2 int64
+
+ t1 = time.Nanoseconds()
+ header, payloadpos, err := cm.ParseHeader(bts)
+ if cm.log {
+ //cm.logger.Logf("err %v header %v\n", err, header)
+ //cm.logger.Logf("header %p\n", header)
+ }
+
+ if err != nil {
+ panic("panic reason: header could not be parsed")
+ }
+ rpc.Header = header
+ t2 = time.Nanoseconds()
+ //fmt.Printf("ParseHeader: %d us\n", (t2-t1)/1000)
+
+ t1 = time.Nanoseconds()
+ payload, err := cm.DecodePayload(header, bts, payloadpos)
+
+ if err != nil {
+ panic("could not decode payload")
+ }
+ rpc.Payload = payload
+ t2 = time.Nanoseconds()
+ //fmt.Printf("DecodePayload: %d us\n", (t2-t1)/1000)
+
+ t1 = time.Nanoseconds()
+ rpcframe, err := cm.ReadRPC(header, payload)
+ if err != nil {
+ fmt.Printf("%v\n", err)
+ panic("could not read RPC")
+ }
+ rpc.RPCFrame = rpcframe
+ t2 = time.Nanoseconds()
+ //fmt.Printf("ReadRPC: %d us\n", (t2-t1)/1000)
+
+ if rpc.Header.Call == 0x01 {
+ rpc.RPCFrame.Args[0] = reflect.NewValue(rpc)
+ }
+
+ t1 = time.Nanoseconds()
+ cm.DispatchRPC(rpc)
+ t2 = time.Nanoseconds()
+ //fmt.Printf("DispatchRPC: %d us\n", (t2-t1)/1000)
+ //fmt.Printf("payload %v\n", rpc.Payload)
+ _ = t2 - t1
+}
+
+
+func (cm *CallManager) Call(addr net.Addr, name string, args []interface{}) (retis []interface{}, err os.Error) {
+
+ cm.logger.Logf("call called\n")
+ fmt.Printf("CALL\n")
+
+ rpc := new(RPC)
+ header := new(Header)
+ rpc.Header = header
+
+ header.Version = 1
+ header.Sender = cm.Id
+ // TODO: DHTId!
+ header.DHTId = nil
+ header.Id = uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
+ header.Call = 0x01
+
+ packet := new(Packet)
+ rpc.Packet = packet
+ packet.To = addr
+
+ rpcframe := new(RPCFrame)
+ rpc.RPCFrame = rpcframe
+ rpcframe.Name = name
+ rpcframe.OutArgs = args
+
+ rpcdesc := make(map[string]interface{})
+ rpcdesc["name"] = name
+ rpcdesc["args"] = args
+
+ rpc.Payload = rpcdesc
+
+ cm.logger.Logf("Call: encoding packet")
+ data := cm.EncodeRPC(rpc)
+ if packet == nil {
+ return nil, RPCError("could not encode packet")
+ }
+ packet.Data = data
+
+
+ // register RPC...
+ running := &RunningRPC{rpc, make(chan *RPC)}
+ cm.regchan <- running
+
+ err = cm.transceiver.SendRPC(rpc)
+ if err != nil {
+ return nil, err
+ }
+
+ retrpc := <-running.retchan
+ if retrpc == nil {
+ return nil, RPCError("time out")
+ }
+
+ if retis, ok := retrpc.Payload.([]interface{}); ok {
+ return retis, nil
+ }
+
+
+ if cm.log {
+ cm.logger.Logf("return payload was not []interface{}\n")
+ }
+ return nil, nil
+
+
+}
+
+func (cm *CallManager) Run() {
+
+ recv := cm.transceiver.GetReceiveChannel()
+
+ go cm.manageRunning()
+
+ for {
+ select {
+ case packet := <-recv:
+ if cm.log {
+ cm.logger.Logf("call manager recvd\n")
+ }
+ go cm.DispatchPacket(packet)
+ // help GC
+ packet = nil
+ }
+ }
+
+}
+
+/*
+
+*/
+
+
+func Ping(rpc *RPC) int64 { return 0x42 }
+
+func Store(rpc *RPC, hash string, data string) int64 {
+ return 1
+}
diff --git a/lib/sleepqueue.go b/lib/sleepqueue.go
new file mode 100644
index 0000000..bb5397e
--- /dev/null
+++ b/lib/sleepqueue.go
@@ -0,0 +1,84 @@
+package malus
+
+
+import "time"
+
+
+// interface sleepqueue?
+
+
+type sleepRequest struct {
+ howlong uint64
+ waketime int64
+ retchan chan bool
+}
+
+type ForwardSleepQueue struct {
+ reqchan chan *sleepRequest
+ quitchan chan bool
+ q chan *sleepRequest
+}
+
+
+func (q *ForwardSleepQueue) Sleep(howlong uint64) {
+ req := new(sleepRequest)
+ req.howlong = howlong
+ req.retchan = make(chan bool)
+
+ q.reqchan <- req
+
+ <- req.retchan
+}
+
+
+
+func (q *ForwardSleepQueue) server() {
+ for {
+ select {
+ case req := <- q.reqchan:
+ req.waketime = time.Nanoseconds() + int64(req.howlong)
+ q.q <- req
+ case <- q.quitchan:
+ return
+ }
+ }
+}
+
+func (q *ForwardSleepQueue) sleeper() {
+ for {
+ select {
+ case req := <- q.reqchan:
+ sleeptime := req.waketime - time.Nanoseconds()
+ for sleeptime > 0 {
+ time.Sleep(sleeptime)
+ sleeptime = req.waketime - time.Nanoseconds()
+ }
+ req.retchan <- true
+ case <- q.quitchan:
+ return
+ }
+ }
+}
+
+func (q *ForwardSleepQueue) Run() {
+ go q.server()
+ go q.sleeper()
+}
+
+
+func (q *ForwardSleepQueue) Stop() {
+ q.quitchan <- true
+ q.quitchan <- true
+}
+
+
+func NewSleepQueue() (q *ForwardSleepQueue) {
+ q = new(ForwardSleepQueue)
+ q.reqchan = make(chan *sleepRequest)
+ q.quitchan = make(chan bool)
+ q.q = make(chan *sleepRequest)
+
+ go q.Run()
+
+ return
+}
diff --git a/lib/udp.go b/lib/udp.go
new file mode 100644
index 0000000..4755d4d
--- /dev/null
+++ b/lib/udp.go
@@ -0,0 +1,83 @@
+package malus
+
+
+import (
+ "os"
+ //"fmt"
+ "net"
+)
+
+
+const (
+ MAXPACKLEN = 2048
+)
+
+type UDPError string;
+func (u UDPError) String() string { return string(u) }
+
+
+
+
+type UDPTransceiver struct {
+ spool chan *Packet
+ incoming chan *RPC
+ conn *net.UDPConn
+}
+
+func NewUDPTransceiver(snet string, laddr *net.UDPAddr) (t *UDPTransceiver) {
+ t = new(UDPTransceiver)
+
+ conn, err := net.ListenUDP(snet, laddr)
+ if err != nil {
+ return nil
+ }
+ t.conn = conn
+ t.spool = make(chan *Packet)
+ t.incoming = make(chan *RPC)
+
+ return t
+}
+
+func (t *UDPTransceiver) SendRPC(rpc *RPC) (err os.Error) {
+ t.incoming <- rpc
+ return
+}
+
+
+func (t *UDPTransceiver) GetReceiveChannel() (c <- chan *Packet) {
+ return t.spool
+}
+
+
+func (t *UDPTransceiver) sendLoop() {
+ for {
+ select {
+ case rpc := <- t.incoming:
+ t.conn.WriteTo(rpc.Packet.Data, rpc.Packet.To)
+ }
+ }
+}
+
+
+func (t *UDPTransceiver) receiveLoop() {
+ for {
+ buf := make([]byte, MAXPACKLEN)
+ n, addr, err := t.conn.ReadFromUDP(buf)
+ if err != nil { continue }
+
+ buf = buf[0:n]
+ pack := new(Packet)
+ pack.Data = buf
+ pack.From = addr
+
+ //fmt.Printf("received pack from %v\n", pack.From)
+
+ t.spool <- pack
+ }
+}
+
+
+func (t *UDPTransceiver) Run() {
+ go t.sendLoop()
+ go t.receiveLoop()
+}
diff --git a/lib/utility.go b/lib/utility.go
new file mode 100644
index 0000000..5ec8d44
--- /dev/null
+++ b/lib/utility.go
@@ -0,0 +1,18 @@
+package malus
+
+import (
+ "crypto/sha1"
+ "strings"
+)
+
+func SHA1Bytes(b []byte) string {
+ h := sha1.New()
+ h.Write(b)
+ return string(h.Sum())
+}
+
+func SHA1String(s string) string {
+ h := sha1.New()
+ h.Write(strings.Bytes(s))
+ return string(h.Sum())
+}
diff --git a/lib/webinterface.go b/lib/webinterface.go
new file mode 100644
index 0000000..2dd43ef
--- /dev/null
+++ b/lib/webinterface.go
@@ -0,0 +1,87 @@
+package malus
+
+
+import (
+ "http"
+ "strings"
+ "fmt"
+ "os"
+ "net"
+ "expvar"
+)
+
+
+type WebInterface struct {
+ addr string
+ cm *CallManager
+ sm *http.ServeMux
+ reqcounter *expvar.Int
+}
+
+
+func NewWebInterface(addr string, cm *CallManager) *WebInterface {
+ wi := new(WebInterface)
+ wi.addr = addr
+ wi.cm = cm
+ wi.sm = http.NewServeMux()
+ wi.reqcounter = expvar.NewInt("")
+
+ wi.sm.Handle("/", http.HandlerFunc(wi.getDummy()))
+
+ return wi
+}
+
+
+
+func (wi *WebInterface) Run() (err os.Error) {
+ err = http.ListenAndServe(wi.addr, wi.sm)
+ return
+}
+
+
+
+// this function wraps handlers defined as methods of a WebInterface
+// struct and binds them to a provided *WebInterface
+func (wi *WebInterface) wrapHandler(f func(*WebInterface, *http.Conn, *http.Request)) (func(*http.Conn, *http.Request)) {
+ fmt.Printf(">> wrapping handler wi %v f %v\n", wi, f)
+ return func(c *http.Conn, r *http.Request) {
+ fmt.Printf("outer handler called with wi %v c %v\n", wi, c)
+ f(wi, c, r)
+ }
+}
+
+
+func (wi *WebInterface) getDummy() (func(*http.Conn, *http.Request)) {
+ dummy := func(c *http.Conn, req *http.Request) {
+ fmt.Printf("incoming request!\n")
+ wi.reqcounter.Add(1)
+ raddr, _ := net.ResolveUDPAddr("127.0.0.1:8001")
+ fmt.Printf("WI calling raddr %v\n", raddr)
+ switch req.FormValue("rpc") {
+ case "ping":
+ c.Write(strings.Bytes("pinging...
"))
+ retis, err := wi.cm.Call(raddr, "ping", make([]interface{}, 0))
+ fmt.Fprintf(c, "=> ping done! err %v retis %v\n", err, retis)
+ case "getsocket":
+ retis, err := wi.cm.Call(raddr, "getsocket", make([]interface{}, 0))
+ fmt.Fprintf(c, "=> getsocket err %v retis %v
\n", err, retis)
+ case "resolve":
+ saddr := req.FormValue("addr")
+ fmt.Printf("resolving addr %q\n", saddr)
+ addr, err := net.ResolveUDPAddr(saddr)
+ if err == nil {
+ fmt.Fprintf(c, "=> addr %v err %v\n", addr, err)
+ } else {
+ fmt.Fprintf(c, "failed to resolve addr! err %v\n", err)
+ }
+ default:
+ c.Write(strings.Bytes("das esch de rap shit: " + req.FormValue("rpc") + "
ping now!
"))
+ fmt.Fprintf(c, "fuck\n")
+ }
+ fmt.Fprintf(c, "
req counter: %s\n", wi.reqcounter.String())
+ }
+
+
+
+ return dummy
+}
diff --git a/main/Makefile b/main/Makefile
new file mode 100644
index 0000000..ae5f0a6
--- /dev/null
+++ b/main/Makefile
@@ -0,0 +1,10 @@
+include $(GOROOT)/src/Make.$(GOARCH)
+
+TARG=malus
+
+GOFILES=\
+ main.go \
+
+
+include $(GOROOT)/src/Make.cmd
+
diff --git a/main/main.go b/main/main.go
new file mode 100644
index 0000000..46b5334
--- /dev/null
+++ b/main/main.go
@@ -0,0 +1,70 @@
+package main
+
+
+import (
+ "malus"
+ "fmt"
+ "net"
+ //"os"
+ //"io/ioutil"
+ //"reflect"
+ "strconv"
+// "http"
+// "strings"
+)
+
+func main() {
+
+ laddr, err := net.ResolveUDPAddr("0.0.0.0:7000")
+ if err != nil {
+ panicln("could not resolve addr")
+ }
+ tr := malus.NewUDPTransceiver("udp", laddr)
+ if tr == nil {
+ panic("could not make transceiver")
+ }
+
+ cm := malus.NewCallManager(tr)
+ cm.Id = malus.SHA1String(strconv.Itoa(laddr.Port))
+ cm.AddRPC("ping", malus.Ping)
+ cm.AddRPC("store", malus.Store)
+
+ fmt.Printf("registered\n")
+
+ /*print(bts)
+ fmt.Printf("\n%v\n", bts)*/
+
+ go tr.Run()
+ go cm.Run()
+
+
+ raddr, _ := net.ResolveUDPAddr("127.0.0.1:8001")
+ fmt.Printf("calling..\n")
+ retis, err := cm.Call(raddr, "ping", make([]interface{}, 0))
+
+ fmt.Printf("=> ping done! \n", err, retis)
+
+
+ {
+ fmt.Printf("creating WI\n")
+ wi := malus.NewWebInterface(":9000", cm)
+ fmt.Printf("now running WI\n")
+ err := wi.Run()
+ if err != nil {
+ fmt.Printf("WI err %v\n", wi)
+ panic("WI panic")
+ }
+ fmt.Printf("WebInterface running\n")
+ }
+
+/* {
+ http.Handle("/", http.HandlerFunc(dummyhandle))
+ err := http.ListenAndServe(":9000", nil)
+ if err != nil {
+ panic("could not ListenAndServe")
+ }
+ }*/
+
+ <-make(chan bool)
+
+}