lib/min_net.nim
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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
import net, nativesockets, strutils, critbits import ../core/types, ../core/parser, ../core/interpreter, ../core/utils # Network var symbols*: CritBitTree[proc(obj: Val, i: In): MinOperator] proc socketSymbol(name: string, body: proc(q: Val, i: In))= symbols[name] = proc(obj: Val, i: In): MinOperator = i.localSymbol(obj, "socket") do (i: In): var q: MinValue i.reqObject "socket", q q.body(i) socketSymbol("domain") do (q: Val, i: In): i.push q.qVal[0].symVal.newVal socketSymbol("type") do (q: Val, i: In): i.push q.qVal[1].symVal.newVal socketSymbol("protocol") do (q: Val, i: In): i.push q.qVal[2].symVal.newVal socketSymbol("close") do (q: Val, i: In): q.to(Socket).close() socketSymbol("listen") do (q: Val, i: In): var port: MinValue i.reqInt port var socket = q.to(Socket) socket.bindAddr(Port(port.intVal)) q.qVal.add "0.0.0.0".newSym q.qVal.add port q.scope.symbols["address"] = proc (i:In) = i.push "0.0.0.0".newVal q.scope.symbols["port"] = proc (i:In) = i.push port socket.listen() define("net") .symbol("^socket") do (i: In): var q: MinValue i.reqQuotation q # (ipv4 stream tcp) if q.qVal.len < 3 or not (q.qVal[0].isSymbol and q.qVal[1].isSymbol and q.qVal[2].isSymbol): raiseInvalid("Quotation must contain three symbols for <domain> <type> <protocol>") let vals = q.qVal if not ["ipv4", "ipv6"].contains(vals[0].symVal): raiseInvalid("Domain symbol must be 'ipv4' or 'ipv6'") if not ["stream", "dgram"].contains(vals[1].symVal): raiseInvalid("Type symbol must be 'stream' or 'dgram'") if not ["tcp", "udp"].contains(vals[2].symVal): raiseInvalid("Protocol symbol must be 'tcp' or 'udp'") var domain: Domain sockettype: SockType protocol: Protocol # Process domain if vals[0].symVal == "ipv4": domain = AF_INET else: domain = AF_INET6 if vals[1].symVal == "stream": sockettype = SOCK_STREAM else: sockettype = SOCK_DGRAM if vals[2].symVal == "tcp": protocol = IPPROTO_TCP else: protocol = IPPROTO_UDP var socket = newSocket(domain, sockettype, protocol) q.objType = "socket" q.obj = socket[].addr i.newScope("<socket>", q) q.scope.symbols["domain"] = symbols["domain"](q, i) q.scope.symbols["type"] = symbols["type"](q, i) q.scope.symbols["protocol"] = symbols["protocol"](q, i) q.scope.symbols["close"] = symbols["close"](q, i) q.scope.symbols["listen"] = symbols["listen"](q, i) i.push @[q] #.symbol("listen") do (i: In): # var port, q: MinValue # i.reqObject "socket", q # i.reqInt port # var socket = q.to(Socket) # socket.bindAddr(Port(port.intVal)) # q.qVal.add "0.0.0.0".newSym # q.qVal.add port # q.scope.symbols["address"] = proc (i:In) = # i.push "0.0.0.0".newVal # q.scope.symbols["port"] = proc (i:In) = # i.push port # socket.listen() # i.push @[q] .symbol("accept") do (i: In): var server: MinValue i.reqObject "socket", server # Open same socket type as server i.eval "$1 net %open-socket" % [$server.qVal[0..2].newVal] var clientVal: MinValue i.reqObject "socket", clientVal var client = clientVal.to(Socket) var address = "" server.to(Socket).acceptAddr(client, address) clientVal.qVal.add address.newSym i.push @[clientVal] .symbol("connect") do (i: In): var q, address, port: MinValue i.reqInt port i.reqString address i.reqObject "socket", q q.to(Socket).connect(address.strVal, Port(port.intVal)) q.qVal.add address.strVal.newSym q.qVal.add port q.scope.symbols["client-address"] = proc (i:In) = i.push address.strVal.newVal q.scope.symbols["client-port"] = proc (i:In) = i.push port i.push @[q] .symbol("send") do (i: In): var q, s: MinValue i.reqString s i.reqObject "socket", q q.to(Socket).send s.strVal i.push @[q] .symbol("recv") do (i: In): var size, q: MinValue i.reqInt size i.reqObject "socket", q var s = "" discard q.to(Socket).recv(s, size.intVal.int) i.push @[q] i.push s.newVal .symbol("recv-line") do (i: In): var q: MinValue i.reqObject "socket", q var s = "" q.to(Socket).readLine(s) i.push @[q] i.push s.newVal .finalize() |