Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
This commit is contained in:
commit
010b8f85c7
16 changed files with 265 additions and 118 deletions
18
doc/lib.txt
18
doc/lib.txt
|
|
@ -18,7 +18,7 @@ low-level interface to a C library.
|
||||||
|
|
||||||
Read this `document <apis.html>`_ for a quick overview of the API design.
|
Read this `document <apis.html>`_ for a quick overview of the API design.
|
||||||
|
|
||||||
The `bottom <#babel>`_ of this page includes a list of 3rd party packages
|
The `bottom <#nimble>`_ of this page includes a list of 3rd party packages
|
||||||
created by the Nim community. These packages are a useful addition to the
|
created by the Nim community. These packages are a useful addition to the
|
||||||
modules in the standard library.
|
modules in the standard library.
|
||||||
|
|
||||||
|
|
@ -581,12 +581,12 @@ Scientific computing
|
||||||
* `libsvm <libsvm.html>`_
|
* `libsvm <libsvm.html>`_
|
||||||
Low level wrapper for `lib svm <http://www.csie.ntu.edu.tw/~cjlin/libsvm/>`_.
|
Low level wrapper for `lib svm <http://www.csie.ntu.edu.tw/~cjlin/libsvm/>`_.
|
||||||
|
|
||||||
Babel
|
Nimble
|
||||||
====================
|
====================
|
||||||
|
|
||||||
Babel is a package manager for the Nim programming language.
|
Nimble is a package manager for the Nim programming language.
|
||||||
For instructions on how to install Babel packages see
|
For instructions on how to install Nimble packages see
|
||||||
`its README <https://github.com/nim-code/babel#readme>`_.
|
`its README <https://github.com/nim-lang/babel#readme>`_.
|
||||||
|
|
||||||
Official packages
|
Official packages
|
||||||
-----------------
|
-----------------
|
||||||
|
|
@ -598,7 +598,7 @@ compiler.
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<div id="officialPkgList"><b>If you are reading this you are missing
|
<div id="officialPkgList"><b>If you are reading this you are missing
|
||||||
babelpkglist.js or have javascript disabled in your browser.</b></div>
|
nimblepkglist.js or have javascript disabled in your browser.</b></div>
|
||||||
|
|
||||||
Unofficial packages
|
Unofficial packages
|
||||||
-------------------
|
-------------------
|
||||||
|
|
@ -610,7 +610,7 @@ Nim programming language.
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<div id="unofficialPkgList"><b>If you are reading this you are missing
|
<div id="unofficialPkgList"><b>If you are reading this you are missing
|
||||||
babelpkglist.js or have javascript disabled in your browser.</b></div>
|
nimblepkglist.js or have javascript disabled in your browser.</b></div>
|
||||||
|
|
||||||
<script type="text/javascript" src="babelpkglist.js"></script>
|
<script type="text/javascript" src="nimblepkglist.js"></script>
|
||||||
<script type="text/javascript" src="http://build.nim-lang.org/packages?callback=gotPackageList"></script>
|
<script type="text/javascript" src="http://irclogs.nim-lang.org/packages?callback=gotPackageList"></script>
|
||||||
|
|
|
||||||
|
|
@ -436,12 +436,12 @@ when defined(windows) or defined(nimdoc):
|
||||||
if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
|
if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
proc connectEx(s: SocketHandle, name: ptr TSockAddr, namelen: cint,
|
proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint,
|
||||||
lpSendBuffer: pointer, dwSendDataLength: Dword,
|
lpSendBuffer: pointer, dwSendDataLength: Dword,
|
||||||
lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool =
|
lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool =
|
||||||
if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().")
|
if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().")
|
||||||
let fun =
|
let fun =
|
||||||
cast[proc (s: SocketHandle, name: ptr TSockAddr, namelen: cint,
|
cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint,
|
||||||
lpSendBuffer: pointer, dwSendDataLength: Dword,
|
lpSendBuffer: pointer, dwSendDataLength: Dword,
|
||||||
lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr)
|
lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr)
|
||||||
|
|
||||||
|
|
@ -464,16 +464,16 @@ when defined(windows) or defined(nimdoc):
|
||||||
|
|
||||||
proc getAcceptExSockaddrs(lpOutputBuffer: pointer,
|
proc getAcceptExSockaddrs(lpOutputBuffer: pointer,
|
||||||
dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: Dword,
|
dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: Dword,
|
||||||
LocalSockaddr: ptr ptr TSockAddr, LocalSockaddrLength: LPInt,
|
LocalSockaddr: ptr ptr SockAddr, LocalSockaddrLength: LPInt,
|
||||||
RemoteSockaddr: ptr ptr TSockAddr, RemoteSockaddrLength: LPInt) =
|
RemoteSockaddr: ptr ptr SockAddr, RemoteSockaddrLength: LPInt) =
|
||||||
if getAcceptExSockAddrsPtr.isNil:
|
if getAcceptExSockAddrsPtr.isNil:
|
||||||
raise newException(ValueError, "Need to initialise getAcceptExSockAddrs().")
|
raise newException(ValueError, "Need to initialise getAcceptExSockAddrs().")
|
||||||
|
|
||||||
let fun =
|
let fun =
|
||||||
cast[proc (lpOutputBuffer: pointer,
|
cast[proc (lpOutputBuffer: pointer,
|
||||||
dwReceiveDataLength, dwLocalAddressLength,
|
dwReceiveDataLength, dwLocalAddressLength,
|
||||||
dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr TSockAddr,
|
dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr SockAddr,
|
||||||
LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr TSockAddr,
|
LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr SockAddr,
|
||||||
RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr)
|
RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr)
|
||||||
|
|
||||||
fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
|
fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
|
||||||
|
|
@ -489,12 +489,12 @@ when defined(windows) or defined(nimdoc):
|
||||||
verifyPresence(socket)
|
verifyPresence(socket)
|
||||||
var retFuture = newFuture[void]("connect")
|
var retFuture = newFuture[void]("connect")
|
||||||
# Apparently ``ConnectEx`` expects the socket to be initially bound:
|
# Apparently ``ConnectEx`` expects the socket to be initially bound:
|
||||||
var saddr: Tsockaddr_in
|
var saddr: Sockaddr_in
|
||||||
saddr.sin_family = int16(toInt(af))
|
saddr.sin_family = int16(toInt(af))
|
||||||
saddr.sin_port = 0
|
saddr.sin_port = 0
|
||||||
saddr.sin_addr.s_addr = INADDR_ANY
|
saddr.sin_addr.s_addr = INADDR_ANY
|
||||||
if bindAddr(socket.SocketHandle, cast[ptr TSockAddr](addr(saddr)),
|
if bindAddr(socket.SocketHandle, cast[ptr SockAddr](addr(saddr)),
|
||||||
sizeof(saddr).TSockLen) < 0'i32:
|
sizeof(saddr).SockLen) < 0'i32:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
var aiList = getAddrInfo(address, port, af)
|
var aiList = getAddrInfo(address, port, af)
|
||||||
|
|
@ -516,7 +516,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
)
|
)
|
||||||
|
|
||||||
var ret = connectEx(socket.SocketHandle, it.ai_addr,
|
var ret = connectEx(socket.SocketHandle, it.ai_addr,
|
||||||
sizeof(Tsockaddr_in).cint, nil, 0, nil,
|
sizeof(Sockaddr_in).cint, nil, 0, nil,
|
||||||
cast[POVERLAPPED](ol))
|
cast[POVERLAPPED](ol))
|
||||||
if ret:
|
if ret:
|
||||||
# Request to connect completed immediately.
|
# Request to connect completed immediately.
|
||||||
|
|
@ -700,17 +700,17 @@ when defined(windows) or defined(nimdoc):
|
||||||
var lpOutputBuf = newString(lpOutputLen)
|
var lpOutputBuf = newString(lpOutputLen)
|
||||||
var dwBytesReceived: Dword
|
var dwBytesReceived: Dword
|
||||||
let dwReceiveDataLength = 0.Dword # We don't want any data to be read.
|
let dwReceiveDataLength = 0.Dword # We don't want any data to be read.
|
||||||
let dwLocalAddressLength = Dword(sizeof (Tsockaddr_in) + 16)
|
let dwLocalAddressLength = Dword(sizeof (Sockaddr_in) + 16)
|
||||||
let dwRemoteAddressLength = Dword(sizeof(Tsockaddr_in) + 16)
|
let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
||||||
|
|
||||||
template completeAccept(): stmt {.immediate, dirty.} =
|
template completeAccept(): stmt {.immediate, dirty.} =
|
||||||
var listenSock = socket
|
var listenSock = socket
|
||||||
let setoptRet = setsockopt(clientSock, SOL_SOCKET,
|
let setoptRet = setsockopt(clientSock, SOL_SOCKET,
|
||||||
SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
|
SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
|
||||||
sizeof(listenSock).TSockLen)
|
sizeof(listenSock).SockLen)
|
||||||
if setoptRet != 0: raiseOSError(osLastError())
|
if setoptRet != 0: raiseOSError(osLastError())
|
||||||
|
|
||||||
var localSockaddr, remoteSockaddr: ptr TSockAddr
|
var localSockaddr, remoteSockaddr: ptr SockAddr
|
||||||
var localLen, remoteLen: int32
|
var localLen, remoteLen: int32
|
||||||
getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength,
|
getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength,
|
||||||
dwLocalAddressLength, dwRemoteAddressLength,
|
dwLocalAddressLength, dwRemoteAddressLength,
|
||||||
|
|
@ -719,7 +719,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
register(clientSock.TAsyncFD)
|
register(clientSock.TAsyncFD)
|
||||||
# TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
|
# TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
|
||||||
retFuture.complete(
|
retFuture.complete(
|
||||||
(address: $inet_ntoa(cast[ptr Tsockaddr_in](remoteSockAddr).sin_addr),
|
(address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr),
|
||||||
client: clientSock.TAsyncFD)
|
client: clientSock.TAsyncFD)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
##
|
##
|
||||||
## .. code-block::nim
|
## .. code-block::nim
|
||||||
## var server = newAsyncHttpServer()
|
## var server = newAsyncHttpServer()
|
||||||
## proc cb(req: TRequest) {.async.} =
|
## proc cb(req: Request) {.async.} =
|
||||||
## await req.respond(Http200, "Hello World")
|
## await req.respond(Http200, "Hello World")
|
||||||
##
|
##
|
||||||
## asyncCheck server.serve(Port(8080), cb)
|
## asyncCheck server.serve(Port(8080), cb)
|
||||||
|
|
@ -27,25 +27,52 @@
|
||||||
import strtabs, asyncnet, asyncdispatch, parseutils, uri, strutils
|
import strtabs, asyncnet, asyncdispatch, parseutils, uri, strutils
|
||||||
type
|
type
|
||||||
Request* = object
|
Request* = object
|
||||||
client*: PAsyncSocket # TODO: Separate this into a Response object?
|
client*: AsyncSocket # TODO: Separate this into a Response object?
|
||||||
reqMethod*: string
|
reqMethod*: string
|
||||||
headers*: PStringTable
|
headers*: StringTableRef
|
||||||
protocol*: tuple[orig: string, major, minor: int]
|
protocol*: tuple[orig: string, major, minor: int]
|
||||||
url*: TUri
|
url*: Uri
|
||||||
hostname*: string ## The hostname of the client that made the request.
|
hostname*: string ## The hostname of the client that made the request.
|
||||||
body*: string
|
body*: string
|
||||||
|
|
||||||
AsyncHttpServer* = ref object
|
AsyncHttpServer* = ref object
|
||||||
socket: PAsyncSocket
|
socket: AsyncSocket
|
||||||
reuseAddr: bool
|
reuseAddr: bool
|
||||||
|
|
||||||
HttpCode* = enum
|
HttpCode* = enum
|
||||||
|
Http100 = "100 Continue",
|
||||||
|
Http101 = "101 Switching Protocols",
|
||||||
Http200 = "200 OK",
|
Http200 = "200 OK",
|
||||||
Http303 = "303 Moved",
|
Http201 = "201 Created",
|
||||||
|
Http202 = "202 Accepted",
|
||||||
|
Http204 = "204 No Content",
|
||||||
|
Http205 = "205 Reset Content",
|
||||||
|
Http206 = "206 Partial Content",
|
||||||
|
Http300 = "300 Multiple Choices",
|
||||||
|
Http301 = "301 Moved Permanently",
|
||||||
|
Http302 = "302 Found",
|
||||||
|
Http303 = "303 See Other",
|
||||||
|
Http304 = "304 Not Modified",
|
||||||
|
Http305 = "305 Use Proxy",
|
||||||
|
Http307 = "307 Temporary Redirect",
|
||||||
Http400 = "400 Bad Request",
|
Http400 = "400 Bad Request",
|
||||||
|
Http401 = "401 Unauthorized",
|
||||||
|
Http403 = "403 Forbidden",
|
||||||
Http404 = "404 Not Found",
|
Http404 = "404 Not Found",
|
||||||
|
Http405 = "405 Method Not Allowed",
|
||||||
|
Http406 = "406 Not Acceptable",
|
||||||
|
Http407 = "407 Proxy Authentication Required",
|
||||||
|
Http408 = "408 Request Timeout",
|
||||||
|
Http409 = "409 Conflict",
|
||||||
|
Http410 = "410 Gone",
|
||||||
|
Http411 = "411 Length Required",
|
||||||
|
Http418 = "418 I'm a teapot",
|
||||||
Http500 = "500 Internal Server Error",
|
Http500 = "500 Internal Server Error",
|
||||||
Http502 = "502 Bad Gateway"
|
Http501 = "501 Not Implemented",
|
||||||
|
Http502 = "502 Bad Gateway",
|
||||||
|
Http503 = "503 Service Unavailable",
|
||||||
|
Http504 = "504 Gateway Timeout",
|
||||||
|
Http505 = "505 HTTP Version Not Supported"
|
||||||
|
|
||||||
HttpVersion* = enum
|
HttpVersion* = enum
|
||||||
HttpVer11,
|
HttpVer11,
|
||||||
|
|
@ -55,7 +82,7 @@ type
|
||||||
THttpCode: HttpCode, THttpVersion: HttpVersion].}
|
THttpCode: HttpCode, THttpVersion: HttpVersion].}
|
||||||
|
|
||||||
proc `==`*(protocol: tuple[orig: string, major, minor: int],
|
proc `==`*(protocol: tuple[orig: string, major, minor: int],
|
||||||
ver: THttpVersion): bool =
|
ver: HttpVersion): bool =
|
||||||
let major =
|
let major =
|
||||||
case ver
|
case ver
|
||||||
of HttpVer11, HttpVer10: 1
|
of HttpVer11, HttpVer10: 1
|
||||||
|
|
@ -65,23 +92,23 @@ proc `==`*(protocol: tuple[orig: string, major, minor: int],
|
||||||
of HttpVer10: 0
|
of HttpVer10: 0
|
||||||
result = protocol.major == major and protocol.minor == minor
|
result = protocol.major == major and protocol.minor == minor
|
||||||
|
|
||||||
proc newAsyncHttpServer*(reuseAddr = true): PAsyncHttpServer =
|
proc newAsyncHttpServer*(reuseAddr = true): AsyncHttpServer =
|
||||||
## Creates a new ``AsyncHttpServer`` instance.
|
## Creates a new ``AsyncHttpServer`` instance.
|
||||||
new result
|
new result
|
||||||
result.reuseAddr = reuseAddr
|
result.reuseAddr = reuseAddr
|
||||||
|
|
||||||
proc addHeaders(msg: var string, headers: PStringTable) =
|
proc addHeaders(msg: var string, headers: StringTableRef) =
|
||||||
for k, v in headers:
|
for k, v in headers:
|
||||||
msg.add(k & ": " & v & "\c\L")
|
msg.add(k & ": " & v & "\c\L")
|
||||||
|
|
||||||
proc sendHeaders*(req: TRequest, headers: PStringTable): Future[void] =
|
proc sendHeaders*(req: Request, headers: StringTableRef): Future[void] =
|
||||||
## Sends the specified headers to the requesting client.
|
## Sends the specified headers to the requesting client.
|
||||||
var msg = ""
|
var msg = ""
|
||||||
addHeaders(msg, headers)
|
addHeaders(msg, headers)
|
||||||
return req.client.send(msg)
|
return req.client.send(msg)
|
||||||
|
|
||||||
proc respond*(req: TRequest, code: THttpCode,
|
proc respond*(req: Request, code: HttpCode,
|
||||||
content: string, headers: PStringTable = newStringTable()) {.async.} =
|
content: string, headers = newStringTable()) {.async.} =
|
||||||
## Responds to the request with the specified ``HttpCode``, headers and
|
## Responds to the request with the specified ``HttpCode``, headers and
|
||||||
## content.
|
## content.
|
||||||
##
|
##
|
||||||
|
|
@ -92,7 +119,7 @@ proc respond*(req: TRequest, code: THttpCode,
|
||||||
msg.addHeaders(customHeaders)
|
msg.addHeaders(customHeaders)
|
||||||
await req.client.send(msg & "\c\L" & content)
|
await req.client.send(msg & "\c\L" & content)
|
||||||
|
|
||||||
proc newRequest(): TRequest =
|
proc newRequest(): Request =
|
||||||
result.headers = newStringTable(modeCaseInsensitive)
|
result.headers = newStringTable(modeCaseInsensitive)
|
||||||
result.hostname = ""
|
result.hostname = ""
|
||||||
result.body = ""
|
result.body = ""
|
||||||
|
|
@ -107,20 +134,20 @@ proc parseHeader(line: string): tuple[key, value: string] =
|
||||||
proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
|
proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
|
||||||
var i = protocol.skipIgnoreCase("HTTP/")
|
var i = protocol.skipIgnoreCase("HTTP/")
|
||||||
if i != 5:
|
if i != 5:
|
||||||
raise newException(EInvalidValue, "Invalid request protocol. Got: " &
|
raise newException(ValueError, "Invalid request protocol. Got: " &
|
||||||
protocol)
|
protocol)
|
||||||
result.orig = protocol
|
result.orig = protocol
|
||||||
i.inc protocol.parseInt(result.major, i)
|
i.inc protocol.parseInt(result.major, i)
|
||||||
i.inc # Skip .
|
i.inc # Skip .
|
||||||
i.inc protocol.parseInt(result.minor, i)
|
i.inc protocol.parseInt(result.minor, i)
|
||||||
|
|
||||||
proc sendStatus(client: PAsyncSocket, status: string): Future[void] =
|
proc sendStatus(client: AsyncSocket, status: string): Future[void] =
|
||||||
client.send("HTTP/1.1 " & status & "\c\L")
|
client.send("HTTP/1.1 " & status & "\c\L")
|
||||||
|
|
||||||
proc processClient(client: PAsyncSocket, address: string,
|
proc processClient(client: AsyncSocket, address: string,
|
||||||
callback: proc (request: TRequest):
|
callback: proc (request: Request):
|
||||||
Future[void] {.closure, gcsafe.}) {.async.} =
|
Future[void] {.closure, gcsafe.}) {.async.} =
|
||||||
while not client.closed:
|
while not client.isClosed:
|
||||||
# GET /path HTTP/1.1
|
# GET /path HTTP/1.1
|
||||||
# Header: val
|
# Header: val
|
||||||
# \n
|
# \n
|
||||||
|
|
@ -160,7 +187,7 @@ proc processClient(client: PAsyncSocket, address: string,
|
||||||
request.url = parseUri(path)
|
request.url = parseUri(path)
|
||||||
try:
|
try:
|
||||||
request.protocol = protocol.parseProtocol()
|
request.protocol = protocol.parseProtocol()
|
||||||
except EInvalidValue:
|
except ValueError:
|
||||||
asyncCheck request.respond(Http400, "Invalid request protocol. Got: " &
|
asyncCheck request.respond(Http400, "Invalid request protocol. Got: " &
|
||||||
protocol)
|
protocol)
|
||||||
continue
|
continue
|
||||||
|
|
@ -206,8 +233,8 @@ proc processClient(client: PAsyncSocket, address: string,
|
||||||
request.client.close()
|
request.client.close()
|
||||||
break
|
break
|
||||||
|
|
||||||
proc serve*(server: PAsyncHttpServer, port: Port,
|
proc serve*(server: AsyncHttpServer, port: Port,
|
||||||
callback: proc (request: TRequest): Future[void] {.closure,gcsafe.},
|
callback: proc (request: Request): Future[void] {.closure,gcsafe.},
|
||||||
address = "") {.async.} =
|
address = "") {.async.} =
|
||||||
## Starts the process of listening for incoming HTTP connections on the
|
## Starts the process of listening for incoming HTTP connections on the
|
||||||
## specified address and port.
|
## specified address and port.
|
||||||
|
|
@ -227,14 +254,14 @@ proc serve*(server: PAsyncHttpServer, port: Port,
|
||||||
#echo(f.isNil)
|
#echo(f.isNil)
|
||||||
#echo(f.repr)
|
#echo(f.repr)
|
||||||
|
|
||||||
proc close*(server: PAsyncHttpServer) =
|
proc close*(server: AsyncHttpServer) =
|
||||||
## Terminates the async http server instance.
|
## Terminates the async http server instance.
|
||||||
server.socket.close()
|
server.socket.close()
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
proc main =
|
proc main =
|
||||||
var server = newAsyncHttpServer()
|
var server = newAsyncHttpServer()
|
||||||
proc cb(req: TRequest) {.async.} =
|
proc cb(req: Request) {.async.} =
|
||||||
#echo(req.reqMethod, " ", req.url)
|
#echo(req.reqMethod, " ", req.url)
|
||||||
#echo(req.headers)
|
#echo(req.headers)
|
||||||
let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT",
|
let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT",
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@ include "system/inclrtl"
|
||||||
|
|
||||||
import sockets, os
|
import sockets, os
|
||||||
|
|
||||||
|
##
|
||||||
|
## **Warning:** This module is deprecated since version 0.10.2.
|
||||||
|
## Use the brand new `asyncdispatch <asyncdispatch.html>`_ module together
|
||||||
|
## with the `asyncnet <asyncnet.html>`_ module.
|
||||||
|
|
||||||
## This module implements an asynchronous event loop together with asynchronous
|
## This module implements an asynchronous event loop together with asynchronous
|
||||||
## sockets which use this event loop.
|
## sockets which use this event loop.
|
||||||
## It is akin to Python's asyncore module. Many modules that use sockets
|
## It is akin to Python's asyncore module. Many modules that use sockets
|
||||||
|
|
@ -90,6 +95,8 @@ import sockets, os
|
||||||
## var client: Socket
|
## var client: Socket
|
||||||
## getSocket(s).accept(client)
|
## getSocket(s).accept(client)
|
||||||
|
|
||||||
|
{.deprecated.}
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
from winlean import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet,
|
from winlean import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet,
|
||||||
FD_ISSET, select
|
FD_ISSET, select
|
||||||
|
|
|
||||||
|
|
@ -69,13 +69,13 @@ type
|
||||||
# TODO: I would prefer to just do:
|
# TODO: I would prefer to just do:
|
||||||
# AsyncSocket* {.borrow: `.`.} = distinct Socket. But that doesn't work.
|
# AsyncSocket* {.borrow: `.`.} = distinct Socket. But that doesn't work.
|
||||||
AsyncSocketDesc = object
|
AsyncSocketDesc = object
|
||||||
fd*: SocketHandle
|
fd: SocketHandle
|
||||||
closed*: bool ## determines whether this socket has been closed
|
closed: bool ## determines whether this socket has been closed
|
||||||
case isBuffered*: bool ## determines whether this socket is buffered.
|
case isBuffered: bool ## determines whether this socket is buffered.
|
||||||
of true:
|
of true:
|
||||||
buffer*: array[0..BufferSize, char]
|
buffer: array[0..BufferSize, char]
|
||||||
currPos*: int # current index in buffer
|
currPos: int # current index in buffer
|
||||||
bufLen*: int # current length of buffer
|
bufLen: int # current length of buffer
|
||||||
of false: nil
|
of false: nil
|
||||||
case isSsl: bool
|
case isSsl: bool
|
||||||
of true:
|
of true:
|
||||||
|
|
@ -91,7 +91,8 @@ type
|
||||||
|
|
||||||
# TODO: Save AF, domain etc info and reuse it in procs which need it like connect.
|
# TODO: Save AF, domain etc info and reuse it in procs which need it like connect.
|
||||||
|
|
||||||
proc newSocket(fd: TAsyncFD, isBuff: bool): AsyncSocket =
|
proc newAsyncSocket*(fd: TAsyncFD, isBuff: bool): AsyncSocket =
|
||||||
|
## Creates a new ``AsyncSocket`` based on the supplied params.
|
||||||
assert fd != osInvalidSocket.TAsyncFD
|
assert fd != osInvalidSocket.TAsyncFD
|
||||||
new(result)
|
new(result)
|
||||||
result.fd = fd.SocketHandle
|
result.fd = fd.SocketHandle
|
||||||
|
|
@ -102,11 +103,17 @@ proc newSocket(fd: TAsyncFD, isBuff: bool): AsyncSocket =
|
||||||
proc newAsyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
proc newAsyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
||||||
protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
|
protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
|
||||||
## Creates a new asynchronous socket.
|
## Creates a new asynchronous socket.
|
||||||
result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
|
##
|
||||||
|
## This procedure will also create a brand new file descriptor for
|
||||||
|
## this socket.
|
||||||
|
result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
|
||||||
|
|
||||||
proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): AsyncSocket =
|
proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): AsyncSocket =
|
||||||
## Creates a new asynchronous socket.
|
## Creates a new asynchronous socket.
|
||||||
result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
|
##
|
||||||
|
## This procedure will also create a brand new file descriptor for
|
||||||
|
## this socket.
|
||||||
|
result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
|
||||||
|
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
proc getSslError(handle: SslPtr, err: cint): cint =
|
proc getSslError(handle: SslPtr, err: cint): cint =
|
||||||
|
|
@ -275,7 +282,7 @@ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
|
||||||
retFuture.fail(future.readError)
|
retFuture.fail(future.readError)
|
||||||
else:
|
else:
|
||||||
let resultTup = (future.read.address,
|
let resultTup = (future.read.address,
|
||||||
newSocket(future.read.client, socket.isBuffered))
|
newAsyncSocket(future.read.client, socket.isBuffered))
|
||||||
retFuture.complete(resultTup)
|
retFuture.complete(resultTup)
|
||||||
return retFuture
|
return retFuture
|
||||||
|
|
||||||
|
|
@ -439,6 +446,18 @@ proc setSockOpt*(socket: AsyncSocket, opt: SOBool, value: bool,
|
||||||
var valuei = cint(if value: 1 else: 0)
|
var valuei = cint(if value: 1 else: 0)
|
||||||
setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
|
setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
|
||||||
|
|
||||||
|
proc isSsl*(socket: AsyncSocket): bool =
|
||||||
|
## Determines whether ``socket`` is a SSL socket.
|
||||||
|
socket.isSsl
|
||||||
|
|
||||||
|
proc getFd*(socket: AsyncSocket): SocketHandle =
|
||||||
|
## Returns the socket's file descriptor.
|
||||||
|
return socket.fd
|
||||||
|
|
||||||
|
proc isClosed*(socket: AsyncSocket): bool =
|
||||||
|
## Determines whether the socket has been closed.
|
||||||
|
return socket.closed
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
type
|
type
|
||||||
TestCases = enum
|
TestCases = enum
|
||||||
|
|
|
||||||
|
|
@ -44,21 +44,21 @@ const
|
||||||
|
|
||||||
type
|
type
|
||||||
SocketImpl* = object ## socket type
|
SocketImpl* = object ## socket type
|
||||||
fd*: SocketHandle
|
fd: SocketHandle
|
||||||
case isBuffered*: bool # determines whether this socket is buffered.
|
case isBuffered: bool # determines whether this socket is buffered.
|
||||||
of true:
|
of true:
|
||||||
buffer*: array[0..BufferSize, char]
|
buffer: array[0..BufferSize, char]
|
||||||
currPos*: int # current index in buffer
|
currPos: int # current index in buffer
|
||||||
bufLen*: int # current length of buffer
|
bufLen: int # current length of buffer
|
||||||
of false: nil
|
of false: nil
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
case isSsl*: bool
|
case isSsl: bool
|
||||||
of true:
|
of true:
|
||||||
sslHandle*: SSLPtr
|
sslHandle: SSLPtr
|
||||||
sslContext*: SSLContext
|
sslContext: SSLContext
|
||||||
sslNoHandshake*: bool # True if needs handshake.
|
sslNoHandshake: bool # True if needs handshake.
|
||||||
sslHasPeekChar*: bool
|
sslHasPeekChar: bool
|
||||||
sslPeekChar*: char
|
sslPeekChar: char
|
||||||
of false: nil
|
of false: nil
|
||||||
|
|
||||||
Socket* = ref SocketImpl
|
Socket* = ref SocketImpl
|
||||||
|
|
@ -100,7 +100,8 @@ proc toOSFlags*(socketFlags: set[SocketFlag]): cint =
|
||||||
result = result or MSG_PEEK
|
result = result or MSG_PEEK
|
||||||
of SocketFlag.SafeDisconn: continue
|
of SocketFlag.SafeDisconn: continue
|
||||||
|
|
||||||
proc createSocket(fd: SocketHandle, isBuff: bool): Socket =
|
proc newSocket(fd: SocketHandle, isBuff: bool): Socket =
|
||||||
|
## Creates a new socket as specified by the params.
|
||||||
assert fd != osInvalidSocket
|
assert fd != osInvalidSocket
|
||||||
new(result)
|
new(result)
|
||||||
result.fd = fd
|
result.fd = fd
|
||||||
|
|
@ -115,7 +116,7 @@ proc newSocket*(domain, typ, protocol: cint, buffered = true): Socket =
|
||||||
let fd = newRawSocket(domain, typ, protocol)
|
let fd = newRawSocket(domain, typ, protocol)
|
||||||
if fd == osInvalidSocket:
|
if fd == osInvalidSocket:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
result = createSocket(fd, buffered)
|
result = newSocket(fd, buffered)
|
||||||
|
|
||||||
proc newSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
proc newSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
||||||
protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
|
protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
|
||||||
|
|
@ -125,7 +126,7 @@ proc newSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
||||||
let fd = newRawSocket(domain, typ, protocol)
|
let fd = newRawSocket(domain, typ, protocol)
|
||||||
if fd == osInvalidSocket:
|
if fd == osInvalidSocket:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
result = createSocket(fd, buffered)
|
result = newSocket(fd, buffered)
|
||||||
|
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
CRYPTO_malloc_init()
|
CRYPTO_malloc_init()
|
||||||
|
|
@ -937,10 +938,10 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
|
||||||
doAssert socket.handshake()
|
doAssert socket.handshake()
|
||||||
socket.fd.setBlocking(true)
|
socket.fd.setBlocking(true)
|
||||||
|
|
||||||
proc isSSL*(socket: Socket): bool = return socket.isSSL
|
proc isSsl*(socket: Socket): bool = return socket.isSSL
|
||||||
## Determines whether ``socket`` is a SSL socket.
|
## Determines whether ``socket`` is a SSL socket.
|
||||||
|
|
||||||
proc getFD*(socket: Socket): SocketHandle = return socket.fd
|
proc getFd*(socket: Socket): SocketHandle = return socket.fd
|
||||||
## Returns the socket's file descriptor
|
## Returns the socket's file descriptor
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,12 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
## Parses & constructs URLs.
|
## **Warnings:** This module is deprecated since version 0.10.2.
|
||||||
|
## Use the `uri <uri.html>`_ module instead.
|
||||||
##
|
##
|
||||||
## **Note**: This module will be deprecated in the future and merged into a
|
## Parses & constructs URLs.
|
||||||
## new ``url`` module.
|
|
||||||
|
{.deprecated.}
|
||||||
|
|
||||||
import strutils
|
import strutils
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,10 @@
|
||||||
##
|
##
|
||||||
## **Warning:** The API of this module is unstable, and therefore is subject
|
## **Warning:** The API of this module is unstable, and therefore is subject
|
||||||
## to change.
|
## to change.
|
||||||
|
##
|
||||||
|
## **Warning:** This module only supports the old asynchronous interface.
|
||||||
|
## You may wish to use the `asynchttpserver <asynchttpserver.html>`_
|
||||||
|
## instead for web applications.
|
||||||
|
|
||||||
include "system/inclrtl"
|
include "system/inclrtl"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,10 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
## **Warning:** Since version 0.10.2 this module is deprecated.
|
||||||
|
## Use the `net <net.html>`_ or the
|
||||||
|
## `rawsockets <rawsockets.html>`_ module instead.
|
||||||
|
##
|
||||||
## This module implements portable sockets, it supports a mix of different types
|
## This module implements portable sockets, it supports a mix of different types
|
||||||
## of sockets. Sockets are buffered by default meaning that data will be
|
## of sockets. Sockets are buffered by default meaning that data will be
|
||||||
## received in ``BufferSize`` (4000) sized chunks, buffering
|
## received in ``BufferSize`` (4000) sized chunks, buffering
|
||||||
|
|
@ -23,9 +27,6 @@
|
||||||
##
|
##
|
||||||
## Asynchronous sockets are supported, however a better alternative is to use
|
## Asynchronous sockets are supported, however a better alternative is to use
|
||||||
## the `asyncio <asyncio.html>`_ module.
|
## the `asyncio <asyncio.html>`_ module.
|
||||||
##
|
|
||||||
## Since version 0.10.2 this module is deprecated. Use the `net <net.html>`_
|
|
||||||
## or the `rawsockets <rawsockets.html>`_ module instead.
|
|
||||||
|
|
||||||
{.deprecated.}
|
{.deprecated.}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,14 @@ type
|
||||||
|
|
||||||
{.deprecated: [TUrl: Url, TUri: Uri].}
|
{.deprecated: [TUrl: Url, TUri: Uri].}
|
||||||
|
|
||||||
proc `$`*(url: TUrl): string {.deprecated.} =
|
proc `$`*(url: Url): string {.deprecated.} =
|
||||||
## **Deprecated since 0.9.6**: Use ``TUri`` instead.
|
## **Deprecated since 0.9.6**: Use ``Uri`` instead.
|
||||||
return string(url)
|
return string(url)
|
||||||
|
|
||||||
proc `/`*(a, b: TUrl): TUrl {.deprecated.} =
|
proc `/`*(a, b: Url): Url {.deprecated.} =
|
||||||
## Joins two URLs together, separating them with / if needed.
|
## Joins two URLs together, separating them with / if needed.
|
||||||
##
|
##
|
||||||
## **Deprecated since 0.9.6**: Use ``TUri`` instead.
|
## **Deprecated since 0.9.6**: Use ``Uri`` instead.
|
||||||
var urlS = $a
|
var urlS = $a
|
||||||
var bS = $b
|
var bS = $b
|
||||||
if urlS == "": return b
|
if urlS == "": return b
|
||||||
|
|
@ -36,15 +36,15 @@ proc `/`*(a, b: TUrl): TUrl {.deprecated.} =
|
||||||
urlS.add(bS.substr(1))
|
urlS.add(bS.substr(1))
|
||||||
else:
|
else:
|
||||||
urlS.add(bs)
|
urlS.add(bs)
|
||||||
result = TUrl(urlS)
|
result = Url(urlS)
|
||||||
|
|
||||||
proc add*(url: var TUrl, a: TUrl) {.deprecated.} =
|
proc add*(url: var Url, a: Url) {.deprecated.} =
|
||||||
## Appends url to url.
|
## Appends url to url.
|
||||||
##
|
##
|
||||||
## **Deprecated since 0.9.6**: Use ``TUri`` instead.
|
## **Deprecated since 0.9.6**: Use ``Uri`` instead.
|
||||||
url = url / a
|
url = url / a
|
||||||
|
|
||||||
proc parseAuthority(authority: string, result: var TUri) =
|
proc parseAuthority(authority: string, result: var Uri) =
|
||||||
var i = 0
|
var i = 0
|
||||||
var inPort = false
|
var inPort = false
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -65,7 +65,7 @@ proc parseAuthority(authority: string, result: var TUri) =
|
||||||
result.hostname.add(authority[i])
|
result.hostname.add(authority[i])
|
||||||
i.inc
|
i.inc
|
||||||
|
|
||||||
proc parsePath(uri: string, i: var int, result: var TUri) =
|
proc parsePath(uri: string, i: var int, result: var Uri) =
|
||||||
|
|
||||||
i.inc parseUntil(uri, result.path, {'?', '#'}, i)
|
i.inc parseUntil(uri, result.path, {'?', '#'}, i)
|
||||||
|
|
||||||
|
|
@ -82,11 +82,11 @@ proc parsePath(uri: string, i: var int, result: var TUri) =
|
||||||
i.inc # Skip '#'
|
i.inc # Skip '#'
|
||||||
i.inc parseUntil(uri, result.anchor, {}, i)
|
i.inc parseUntil(uri, result.anchor, {}, i)
|
||||||
|
|
||||||
proc initUri(): TUri =
|
proc initUri(): Uri =
|
||||||
result = TUri(scheme: "", username: "", password: "", hostname: "", port: "",
|
result = Uri(scheme: "", username: "", password: "", hostname: "", port: "",
|
||||||
path: "", query: "", anchor: "")
|
path: "", query: "", anchor: "")
|
||||||
|
|
||||||
proc parseUri*(uri: string): TUri =
|
proc parseUri*(uri: string): Uri =
|
||||||
## Parses a URI.
|
## Parses a URI.
|
||||||
result = initUri()
|
result = initUri()
|
||||||
|
|
||||||
|
|
@ -113,7 +113,7 @@ proc parseUri*(uri: string): TUri =
|
||||||
var authority = ""
|
var authority = ""
|
||||||
i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
|
i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
|
||||||
if authority == "":
|
if authority == "":
|
||||||
raise newException(EInvalidValue, "Expected authority got nothing.")
|
raise newException(ValueError, "Expected authority got nothing.")
|
||||||
parseAuthority(authority, result)
|
parseAuthority(authority, result)
|
||||||
|
|
||||||
# Path
|
# Path
|
||||||
|
|
@ -150,7 +150,7 @@ proc removeDotSegments(path: string): string =
|
||||||
result = collection.join("/")
|
result = collection.join("/")
|
||||||
if endsWithSlash: result.add '/'
|
if endsWithSlash: result.add '/'
|
||||||
|
|
||||||
proc merge(base, reference: TUri): string =
|
proc merge(base, reference: Uri): string =
|
||||||
# http://tools.ietf.org/html/rfc3986#section-5.2.3
|
# http://tools.ietf.org/html/rfc3986#section-5.2.3
|
||||||
if base.hostname != "" and base.path == "":
|
if base.hostname != "" and base.path == "":
|
||||||
'/' & reference.path
|
'/' & reference.path
|
||||||
|
|
@ -161,7 +161,7 @@ proc merge(base, reference: TUri): string =
|
||||||
else:
|
else:
|
||||||
base.path[0 .. lastSegment] & reference.path
|
base.path[0 .. lastSegment] & reference.path
|
||||||
|
|
||||||
proc combine*(base: TUri, reference: TUri): TUri =
|
proc combine*(base: Uri, reference: Uri): Uri =
|
||||||
## Combines a base URI with a reference URI.
|
## Combines a base URI with a reference URI.
|
||||||
##
|
##
|
||||||
## This uses the algorithm specified in
|
## This uses the algorithm specified in
|
||||||
|
|
@ -216,13 +216,13 @@ proc combine*(base: TUri, reference: TUri): TUri =
|
||||||
result.scheme = base.scheme
|
result.scheme = base.scheme
|
||||||
result.anchor = reference.anchor
|
result.anchor = reference.anchor
|
||||||
|
|
||||||
proc combine*(uris: varargs[TUri]): TUri =
|
proc combine*(uris: varargs[Uri]): Uri =
|
||||||
## Combines multiple URIs together.
|
## Combines multiple URIs together.
|
||||||
result = uris[0]
|
result = uris[0]
|
||||||
for i in 1 .. <uris.len:
|
for i in 1 .. <uris.len:
|
||||||
result = combine(result, uris[i])
|
result = combine(result, uris[i])
|
||||||
|
|
||||||
proc `/`*(x: TUri, path: string): TUri =
|
proc `/`*(x: Uri, path: string): Uri =
|
||||||
## Concatenates the path specified to the specified URI's path.
|
## Concatenates the path specified to the specified URI's path.
|
||||||
##
|
##
|
||||||
## Contrary to the ``combine`` procedure you do not have to worry about
|
## Contrary to the ``combine`` procedure you do not have to worry about
|
||||||
|
|
@ -251,7 +251,7 @@ proc `/`*(x: TUri, path: string): TUri =
|
||||||
result.path.add '/'
|
result.path.add '/'
|
||||||
result.path.add(path)
|
result.path.add(path)
|
||||||
|
|
||||||
proc `$`*(u: TUri): string =
|
proc `$`*(u: Uri): string =
|
||||||
## Returns the string representation of the specified URI object.
|
## Returns the string representation of the specified URI object.
|
||||||
result = ""
|
result = ""
|
||||||
if u.scheme.len > 0:
|
if u.scheme.len > 0:
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,7 @@ proc createServer(port: TPort) {.async.} =
|
||||||
|
|
||||||
discard server.SocketHandle.listen()
|
discard server.SocketHandle.listen()
|
||||||
while true:
|
while true:
|
||||||
var client = await accept(server)
|
asyncCheck readMessages(await accept(server))
|
||||||
asyncCheck readMessages(client)
|
|
||||||
# TODO: Test: readMessages(disp, await disp.accept(server))
|
|
||||||
|
|
||||||
asyncCheck createServer(TPort(10335))
|
asyncCheck createServer(TPort(10335))
|
||||||
asyncCheck launchSwarm(TPort(10335))
|
asyncCheck launchSwarm(TPort(10335))
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ proc serverAccept(s: PAsyncSocket) =
|
||||||
proc launchSwarm(disp: var PDispatcher, port: TPort, count: int,
|
proc launchSwarm(disp: var PDispatcher, port: TPort, count: int,
|
||||||
buffered = true, useSSL = false) =
|
buffered = true, useSSL = false) =
|
||||||
for i in 1..count:
|
for i in 1..count:
|
||||||
var client = AsyncSocket()
|
var client = asyncSocket()
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
if useSSL:
|
if useSSL:
|
||||||
ctx1.wrapSocket(client)
|
ctx1.wrapSocket(client)
|
||||||
|
|
@ -56,7 +56,7 @@ proc launchSwarm(disp: var PDispatcher, port: TPort, count: int,
|
||||||
client.connect("localhost", port)
|
client.connect("localhost", port)
|
||||||
|
|
||||||
proc createSwarm(port: TPort, buffered = true, useSSL = false) =
|
proc createSwarm(port: TPort, buffered = true, useSSL = false) =
|
||||||
var server = AsyncSocket()
|
var server = asyncSocket()
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
if useSSL:
|
if useSSL:
|
||||||
ctx.wrapSocket(server)
|
ctx.wrapSocket(server)
|
||||||
|
|
|
||||||
|
|
@ -42,14 +42,14 @@ proc swarmConnect(s: PAsyncSocket) =
|
||||||
proc createClient(disp: var PDispatcher, port: TPort,
|
proc createClient(disp: var PDispatcher, port: TPort,
|
||||||
buffered = true) =
|
buffered = true) =
|
||||||
currentClient.inc()
|
currentClient.inc()
|
||||||
var client = AsyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
|
var client = asyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
|
||||||
buffered = buffered)
|
buffered = buffered)
|
||||||
client.handleConnect = swarmConnect
|
client.handleConnect = swarmConnect
|
||||||
disp.register(client)
|
disp.register(client)
|
||||||
client.connect("localhost", port)
|
client.connect("localhost", port)
|
||||||
|
|
||||||
proc createServer(port: TPort, buffered = true) =
|
proc createServer(port: TPort, buffered = true) =
|
||||||
var server = AsyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
|
var server = asyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
|
||||||
buffered = buffered)
|
buffered = buffered)
|
||||||
server.handleRead = serverRead
|
server.handleRead = serverRead
|
||||||
disp.register(server)
|
disp.register(server)
|
||||||
|
|
@ -75,4 +75,4 @@ while true:
|
||||||
break
|
break
|
||||||
|
|
||||||
assert msgCount == messagesToSend * serverCount * swarmSize
|
assert msgCount == messagesToSend * serverCount * swarmSize
|
||||||
echo(msgCount)
|
echo(msgCount)
|
||||||
|
|
|
||||||
|
|
@ -396,8 +396,8 @@ proc buildNewsRss(c: var TConfigData, destPath: string) =
|
||||||
generateRss(destFilename, parseNewsTitles(srcFilename))
|
generateRss(destFilename, parseNewsTitles(srcFilename))
|
||||||
|
|
||||||
proc buildJS(destPath: string) =
|
proc buildJS(destPath: string) =
|
||||||
exec("nim js -d:release --out:$1 web/babelpkglist.nim" %
|
exec("nim js -d:release --out:$1 web/nimblepkglist.nim" %
|
||||||
[destPath / "babelpkglist.js"])
|
[destPath / "nimblepkglist.js"])
|
||||||
|
|
||||||
proc buildWebsite(c: var TConfigData) =
|
proc buildWebsite(c: var TConfigData) =
|
||||||
const
|
const
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ proc processContent(content: string) =
|
||||||
dot = if desc.high > 0 and desc[desc.high] in endings: "" else: "."
|
dot = if desc.high > 0 and desc[desc.high] in endings: "" else: "."
|
||||||
listItem = li(a(href=pkgWeb, pkg["name"].str), " ", desc & dot)
|
listItem = li(a(href=pkgWeb, pkg["name"].str), " ", desc & dot)
|
||||||
if pkg["url"].str.startsWith("git://github.com/nimrod-code") or
|
if pkg["url"].str.startsWith("git://github.com/nimrod-code") or
|
||||||
|
pkg["url"].str.startsWith("git://github.com/nim-lang") or
|
||||||
"official" in pkg["tags"].elems:
|
"official" in pkg["tags"].elems:
|
||||||
officialCount.inc
|
officialCount.inc
|
||||||
officialList.add listItem & "\n"
|
officialList.add listItem & "\n"
|
||||||
|
|
@ -52,14 +53,14 @@ proc processContent(content: string) =
|
||||||
|
|
||||||
officialPkgListDiv.innerHTML =
|
officialPkgListDiv.innerHTML =
|
||||||
p("There are currently " & $officialCount &
|
p("There are currently " & $officialCount &
|
||||||
" official packages in the Babel package repository.") &
|
" official packages in the Nimble package repository.") &
|
||||||
ul(officialList)
|
ul(officialList)
|
||||||
|
|
||||||
var unofficialPkgListDiv = document.getElementById("unofficialPkgList")
|
var unofficialPkgListDiv = document.getElementById("unofficialPkgList")
|
||||||
|
|
||||||
unofficialPkgListDiv.innerHTML =
|
unofficialPkgListDiv.innerHTML =
|
||||||
p("There are currently " & $unofficialCount &
|
p("There are currently " & $unofficialCount &
|
||||||
" unofficial packages in the Babel package repository.") &
|
" unofficial packages in the Nimble package repository.") &
|
||||||
ul(unofficialList)
|
ul(unofficialList)
|
||||||
|
|
||||||
proc gotPackageList(apiReply: TData) {.exportc.} =
|
proc gotPackageList(apiReply: TData) {.exportc.} =
|
||||||
|
|
|
||||||
103
web/news.txt
103
web/news.txt
|
|
@ -6,14 +6,67 @@ News
|
||||||
2014-10-21 Version 0.10.2 released
|
2014-10-21 Version 0.10.2 released
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
This release is the latest release before the release canditates for version
|
This release marks the completion of a very important change to the project:
|
||||||
1.0 roll in. Starting with version 0.10.2 the rename of the language to Nim
|
the official renaming from Nimrod to Nim. Version 0.10.2 contains many language
|
||||||
is officially complete. As the list of language changes is quite long it's
|
changes, some of which may break your existing code. For your convenience, we
|
||||||
much more work to update the average Nim project than used to be the case.
|
added a new tool called `nimfix <nimfix.html>`_ that will help you convert your
|
||||||
However there is a new tool, `nimfix <nimfix.html>`_ to help you
|
existing projects so that it works with the latest version of the compiler.
|
||||||
in updating your code from Nimrod to Nim. This tool is unfortunately not
|
|
||||||
perfect but has been used to update thousands of lines of code successfully.
|
|
||||||
|
|
||||||
|
Progress towards version 1.0
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Although Nim is still pre-1.0, we were able to keep the number of breaking
|
||||||
|
changes to a minimum so far. Starting with version 1.0, we will not introduce
|
||||||
|
any breaking changes between major release versions.
|
||||||
|
One of Nim's goals is to ensure that the compiler is as efficient as possible.
|
||||||
|
Take a look at the
|
||||||
|
`latest benchmarks <https://github.com/logicchains/LPATHBench/blob/master/writeup.md>`_,
|
||||||
|
which show that Nim is consistently near
|
||||||
|
the top and already nearly as fast as C and C++. Recent developments, such as
|
||||||
|
the new ``asyncdispatch`` module will allow you to write efficient web server
|
||||||
|
applications using non-blocking code. Nim now also has a built-in thread pool
|
||||||
|
for lightweight threading through the use of ``spawn``.
|
||||||
|
|
||||||
|
The unpopular "T" and "P" prefixes on types have been deprecated. Nim also
|
||||||
|
became more expressive by weakening the distinction between statements and
|
||||||
|
epxressions. We also added new and searchable forums, a new website, and our
|
||||||
|
documentation generator ``docgen`` has seen major improvements.
|
||||||
|
|
||||||
|
What's left to be done
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The 1.0 release is actually very close. There are only a couple of last
|
||||||
|
things that need to be done:
|
||||||
|
|
||||||
|
* Implementing static[T] properly
|
||||||
|
* Support for the overloading of the assignment operator
|
||||||
|
|
||||||
|
Of course, the 1.0 release is not an end to the development of Nim.
|
||||||
|
It is very much the beginning and we will be fleshing out the then
|
||||||
|
stable language.
|
||||||
|
|
||||||
|
Nimble and other Nim tools
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Outside of the language and the compiler itself many Nim tools have seen
|
||||||
|
considerable improvements.
|
||||||
|
|
||||||
|
Babel the Nim package manager has been renamed to Nimble. Nimble's purpose
|
||||||
|
is the installation of packages containing libraries and/or applications
|
||||||
|
written in Nim.
|
||||||
|
Even though Nimble is still very young it already is very
|
||||||
|
functional. It can install packages by name, it does so by accessing a
|
||||||
|
packages repository which is hosted on a Github repo. Packages can also be
|
||||||
|
installed via a Git repo URL or Mercurial repo URL. The package repository
|
||||||
|
is searchable through Nimble. Anyone is free to add their own packages to
|
||||||
|
the package repository by forking the
|
||||||
|
`nim-lang/packages <https://github.com/nim-lang/packages>`_ repo and creating
|
||||||
|
a pull request. Nimble is fully cross-platform and should be fully functional
|
||||||
|
on all major operating systems.
|
||||||
|
It is of course completely written in Nim.
|
||||||
|
|
||||||
|
Changelog
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
Changes affecting backwards compatibility
|
Changes affecting backwards compatibility
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
@ -93,7 +146,7 @@ News
|
||||||
statement.
|
statement.
|
||||||
- There is a new tool, `nimfix <nimfix.html>`_ to help you in updating your
|
- There is a new tool, `nimfix <nimfix.html>`_ to help you in updating your
|
||||||
code from Nimrod to Nim.
|
code from Nimrod to Nim.
|
||||||
|
- The compiler's output has been prettified.
|
||||||
|
|
||||||
Library Additions
|
Library Additions
|
||||||
-----------------
|
-----------------
|
||||||
|
|
@ -103,7 +156,41 @@ News
|
||||||
- ``system.setupForeignThreadGc`` can be used for better interaction with
|
- ``system.setupForeignThreadGc`` can be used for better interaction with
|
||||||
foreign libraries that create threads and run a Nim callback from these
|
foreign libraries that create threads and run a Nim callback from these
|
||||||
foreign threads.
|
foreign threads.
|
||||||
|
- List comprehensions have been implemented as a macro in the ``future``
|
||||||
|
module.
|
||||||
|
- The new Async module (``asyncnet``) now supports SSL.
|
||||||
|
- The ``smtp`` module now has an async implementation.
|
||||||
|
- Added module ``asyncfile`` which implements asynchronous file reading
|
||||||
|
and writing.
|
||||||
|
- ``osproc.kill`` has been added.
|
||||||
|
- ``asyncnet`` and ``asynchttpserver`` now support ``SO_REUSEADDR``.
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- ``nil`` and ``NULL`` are now preserved between Nim and databases in the
|
||||||
|
``db_*`` modules.
|
||||||
|
- Fixed issue with OS module in non-unicode mode on Windows.
|
||||||
|
- Fixed issue with ``x.low``
|
||||||
|
(`#1366 <https://github.com/Araq/Nim/issues/1366>`_).
|
||||||
|
- Fixed tuple unpacking issue inside closure iterators
|
||||||
|
(`#1067 <https://github.com/Araq/Nim/issues/1067>`_).
|
||||||
|
- Fixed ENDB compilation issues.
|
||||||
|
- Many ``asynchttpserver`` fixes.
|
||||||
|
- Macros can now keep global state across macro calls
|
||||||
|
(`#903 <https://github.com/Araq/Nim/issues/903>`_).
|
||||||
|
- ``osproc`` fixes on Windows.
|
||||||
|
- ``osproc.terminate`` fixed.
|
||||||
|
- Improvements to exception handling in async procedures.
|
||||||
|
(`#1487 <https://github.com/Araq/Nim/issues/1487>`_).
|
||||||
|
- ``try`` now works at compile-time.
|
||||||
|
- Fixes ``T = ref T`` to be an illegal recursive type.
|
||||||
|
- Self imports are now disallowed.
|
||||||
|
- Improved effect inference.
|
||||||
|
- Fixes for the ``math`` module on Windows.
|
||||||
|
- User defined pragmas will now work for generics that have
|
||||||
|
been instantiated in different modules.
|
||||||
|
- Fixed queue exhaustion bug.
|
||||||
|
|
||||||
2014-12-09 New website design!
|
2014-12-09 New website design!
|
||||||
==============================
|
==============================
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue