Merge branch 'devel' of https://github.com/Araq/Nimrod into devel

This commit is contained in:
Araq
2014-12-26 22:43:40 +01:00
16 changed files with 265 additions and 118 deletions

View File

@@ -18,7 +18,7 @@ low-level interface to a C library.
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
modules in the standard library.
@@ -581,12 +581,12 @@ Scientific computing
* `libsvm <libsvm.html>`_
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.
For instructions on how to install Babel packages see
`its README <https://github.com/nim-code/babel#readme>`_.
Nimble is a package manager for the Nim programming language.
For instructions on how to install Nimble packages see
`its README <https://github.com/nim-lang/babel#readme>`_.
Official packages
-----------------
@@ -598,7 +598,7 @@ compiler.
.. raw:: html
<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
-------------------
@@ -610,7 +610,7 @@ Nim programming language.
.. raw:: html
<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="http://build.nim-lang.org/packages?callback=gotPackageList"></script>
<script type="text/javascript" src="nimblepkglist.js"></script>
<script type="text/javascript" src="http://irclogs.nim-lang.org/packages?callback=gotPackageList"></script>

View File

@@ -436,12 +436,12 @@ when defined(windows) or defined(nimdoc):
if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
raiseOSError(osLastError())
proc connectEx(s: SocketHandle, name: ptr TSockAddr, namelen: cint,
proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint,
lpSendBuffer: pointer, dwSendDataLength: Dword,
lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool =
if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().")
let fun =
cast[proc (s: SocketHandle, name: ptr TSockAddr, namelen: cint,
cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint,
lpSendBuffer: pointer, dwSendDataLength: Dword,
lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr)
@@ -464,16 +464,16 @@ when defined(windows) or defined(nimdoc):
proc getAcceptExSockaddrs(lpOutputBuffer: pointer,
dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: Dword,
LocalSockaddr: ptr ptr TSockAddr, LocalSockaddrLength: LPInt,
RemoteSockaddr: ptr ptr TSockAddr, RemoteSockaddrLength: LPInt) =
LocalSockaddr: ptr ptr SockAddr, LocalSockaddrLength: LPInt,
RemoteSockaddr: ptr ptr SockAddr, RemoteSockaddrLength: LPInt) =
if getAcceptExSockAddrsPtr.isNil:
raise newException(ValueError, "Need to initialise getAcceptExSockAddrs().")
let fun =
cast[proc (lpOutputBuffer: pointer,
dwReceiveDataLength, dwLocalAddressLength,
dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr TSockAddr,
LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr TSockAddr,
dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr SockAddr,
LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr SockAddr,
RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr)
fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
@@ -489,12 +489,12 @@ when defined(windows) or defined(nimdoc):
verifyPresence(socket)
var retFuture = newFuture[void]("connect")
# 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_port = 0
saddr.sin_addr.s_addr = INADDR_ANY
if bindAddr(socket.SocketHandle, cast[ptr TSockAddr](addr(saddr)),
sizeof(saddr).TSockLen) < 0'i32:
if bindAddr(socket.SocketHandle, cast[ptr SockAddr](addr(saddr)),
sizeof(saddr).SockLen) < 0'i32:
raiseOSError(osLastError())
var aiList = getAddrInfo(address, port, af)
@@ -516,7 +516,7 @@ when defined(windows) or defined(nimdoc):
)
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))
if ret:
# Request to connect completed immediately.
@@ -700,17 +700,17 @@ when defined(windows) or defined(nimdoc):
var lpOutputBuf = newString(lpOutputLen)
var dwBytesReceived: Dword
let dwReceiveDataLength = 0.Dword # We don't want any data to be read.
let dwLocalAddressLength = Dword(sizeof (Tsockaddr_in) + 16)
let dwRemoteAddressLength = Dword(sizeof(Tsockaddr_in) + 16)
let dwLocalAddressLength = Dword(sizeof (Sockaddr_in) + 16)
let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16)
template completeAccept(): stmt {.immediate, dirty.} =
var listenSock = socket
let setoptRet = setsockopt(clientSock, SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
sizeof(listenSock).TSockLen)
sizeof(listenSock).SockLen)
if setoptRet != 0: raiseOSError(osLastError())
var localSockaddr, remoteSockaddr: ptr TSockAddr
var localSockaddr, remoteSockaddr: ptr SockAddr
var localLen, remoteLen: int32
getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength,
dwLocalAddressLength, dwRemoteAddressLength,
@@ -719,7 +719,7 @@ when defined(windows) or defined(nimdoc):
register(clientSock.TAsyncFD)
# TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
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)
)

View File

@@ -18,7 +18,7 @@
##
## .. code-block::nim
## var server = newAsyncHttpServer()
## proc cb(req: TRequest) {.async.} =
## proc cb(req: Request) {.async.} =
## await req.respond(Http200, "Hello World")
##
## asyncCheck server.serve(Port(8080), cb)
@@ -27,25 +27,52 @@
import strtabs, asyncnet, asyncdispatch, parseutils, uri, strutils
type
Request* = object
client*: PAsyncSocket # TODO: Separate this into a Response object?
client*: AsyncSocket # TODO: Separate this into a Response object?
reqMethod*: string
headers*: PStringTable
headers*: StringTableRef
protocol*: tuple[orig: string, major, minor: int]
url*: TUri
url*: Uri
hostname*: string ## The hostname of the client that made the request.
body*: string
AsyncHttpServer* = ref object
socket: PAsyncSocket
socket: AsyncSocket
reuseAddr: bool
HttpCode* = enum
Http100 = "100 Continue",
Http101 = "101 Switching Protocols",
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",
Http401 = "401 Unauthorized",
Http403 = "403 Forbidden",
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",
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
HttpVer11,
@@ -55,7 +82,7 @@ type
THttpCode: HttpCode, THttpVersion: HttpVersion].}
proc `==`*(protocol: tuple[orig: string, major, minor: int],
ver: THttpVersion): bool =
ver: HttpVersion): bool =
let major =
case ver
of HttpVer11, HttpVer10: 1
@@ -65,23 +92,23 @@ proc `==`*(protocol: tuple[orig: string, major, minor: int],
of HttpVer10: 0
result = protocol.major == major and protocol.minor == minor
proc newAsyncHttpServer*(reuseAddr = true): PAsyncHttpServer =
proc newAsyncHttpServer*(reuseAddr = true): AsyncHttpServer =
## Creates a new ``AsyncHttpServer`` instance.
new result
result.reuseAddr = reuseAddr
proc addHeaders(msg: var string, headers: PStringTable) =
proc addHeaders(msg: var string, headers: StringTableRef) =
for k, v in headers:
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.
var msg = ""
addHeaders(msg, headers)
return req.client.send(msg)
proc respond*(req: TRequest, code: THttpCode,
content: string, headers: PStringTable = newStringTable()) {.async.} =
proc respond*(req: Request, code: HttpCode,
content: string, headers = newStringTable()) {.async.} =
## Responds to the request with the specified ``HttpCode``, headers and
## content.
##
@@ -92,7 +119,7 @@ proc respond*(req: TRequest, code: THttpCode,
msg.addHeaders(customHeaders)
await req.client.send(msg & "\c\L" & content)
proc newRequest(): TRequest =
proc newRequest(): Request =
result.headers = newStringTable(modeCaseInsensitive)
result.hostname = ""
result.body = ""
@@ -107,20 +134,20 @@ proc parseHeader(line: string): tuple[key, value: string] =
proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
var i = protocol.skipIgnoreCase("HTTP/")
if i != 5:
raise newException(EInvalidValue, "Invalid request protocol. Got: " &
raise newException(ValueError, "Invalid request protocol. Got: " &
protocol)
result.orig = protocol
i.inc protocol.parseInt(result.major, i)
i.inc # Skip .
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")
proc processClient(client: PAsyncSocket, address: string,
callback: proc (request: TRequest):
proc processClient(client: AsyncSocket, address: string,
callback: proc (request: Request):
Future[void] {.closure, gcsafe.}) {.async.} =
while not client.closed:
while not client.isClosed:
# GET /path HTTP/1.1
# Header: val
# \n
@@ -160,7 +187,7 @@ proc processClient(client: PAsyncSocket, address: string,
request.url = parseUri(path)
try:
request.protocol = protocol.parseProtocol()
except EInvalidValue:
except ValueError:
asyncCheck request.respond(Http400, "Invalid request protocol. Got: " &
protocol)
continue
@@ -206,8 +233,8 @@ proc processClient(client: PAsyncSocket, address: string,
request.client.close()
break
proc serve*(server: PAsyncHttpServer, port: Port,
callback: proc (request: TRequest): Future[void] {.closure,gcsafe.},
proc serve*(server: AsyncHttpServer, port: Port,
callback: proc (request: Request): Future[void] {.closure,gcsafe.},
address = "") {.async.} =
## Starts the process of listening for incoming HTTP connections on the
## specified address and port.
@@ -227,14 +254,14 @@ proc serve*(server: PAsyncHttpServer, port: Port,
#echo(f.isNil)
#echo(f.repr)
proc close*(server: PAsyncHttpServer) =
proc close*(server: AsyncHttpServer) =
## Terminates the async http server instance.
server.socket.close()
when isMainModule:
proc main =
var server = newAsyncHttpServer()
proc cb(req: TRequest) {.async.} =
proc cb(req: Request) {.async.} =
#echo(req.reqMethod, " ", req.url)
#echo(req.headers)
let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT",

View File

@@ -10,6 +10,11 @@ include "system/inclrtl"
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
## sockets which use this event loop.
## It is akin to Python's asyncore module. Many modules that use sockets
@@ -90,6 +95,8 @@ import sockets, os
## var client: Socket
## getSocket(s).accept(client)
{.deprecated.}
when defined(windows):
from winlean import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet,
FD_ISSET, select

View File

@@ -69,13 +69,13 @@ type
# TODO: I would prefer to just do:
# AsyncSocket* {.borrow: `.`.} = distinct Socket. But that doesn't work.
AsyncSocketDesc = object
fd*: SocketHandle
closed*: bool ## determines whether this socket has been closed
case isBuffered*: bool ## determines whether this socket is buffered.
fd: SocketHandle
closed: bool ## determines whether this socket has been closed
case isBuffered: bool ## determines whether this socket is buffered.
of true:
buffer*: array[0..BufferSize, char]
currPos*: int # current index in buffer
bufLen*: int # current length of buffer
buffer: array[0..BufferSize, char]
currPos: int # current index in buffer
bufLen: int # current length of buffer
of false: nil
case isSsl: bool
of true:
@@ -91,7 +91,8 @@ type
# 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
new(result)
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,
protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
## 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 =
## 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):
proc getSslError(handle: SslPtr, err: cint): cint =
@@ -275,7 +282,7 @@ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
retFuture.fail(future.readError)
else:
let resultTup = (future.read.address,
newSocket(future.read.client, socket.isBuffered))
newAsyncSocket(future.read.client, socket.isBuffered))
retFuture.complete(resultTup)
return retFuture
@@ -439,6 +446,18 @@ proc setSockOpt*(socket: AsyncSocket, opt: SOBool, value: bool,
var valuei = cint(if value: 1 else: 0)
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:
type
TestCases = enum

View File

@@ -44,21 +44,21 @@ const
type
SocketImpl* = object ## socket type
fd*: SocketHandle
case isBuffered*: bool # determines whether this socket is buffered.
fd: SocketHandle
case isBuffered: bool # determines whether this socket is buffered.
of true:
buffer*: array[0..BufferSize, char]
currPos*: int # current index in buffer
bufLen*: int # current length of buffer
buffer: array[0..BufferSize, char]
currPos: int # current index in buffer
bufLen: int # current length of buffer
of false: nil
when defined(ssl):
case isSsl*: bool
case isSsl: bool
of true:
sslHandle*: SSLPtr
sslContext*: SSLContext
sslNoHandshake*: bool # True if needs handshake.
sslHasPeekChar*: bool
sslPeekChar*: char
sslHandle: SSLPtr
sslContext: SSLContext
sslNoHandshake: bool # True if needs handshake.
sslHasPeekChar: bool
sslPeekChar: char
of false: nil
Socket* = ref SocketImpl
@@ -100,7 +100,8 @@ proc toOSFlags*(socketFlags: set[SocketFlag]): cint =
result = result or MSG_PEEK
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
new(result)
result.fd = fd
@@ -115,7 +116,7 @@ proc newSocket*(domain, typ, protocol: cint, buffered = true): Socket =
let fd = newRawSocket(domain, typ, protocol)
if fd == osInvalidSocket:
raiseOSError(osLastError())
result = createSocket(fd, buffered)
result = newSocket(fd, buffered)
proc newSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
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)
if fd == osInvalidSocket:
raiseOSError(osLastError())
result = createSocket(fd, buffered)
result = newSocket(fd, buffered)
when defined(ssl):
CRYPTO_malloc_init()
@@ -937,10 +938,10 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
doAssert socket.handshake()
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.
proc getFD*(socket: Socket): SocketHandle = return socket.fd
proc getFd*(socket: Socket): SocketHandle = return socket.fd
## Returns the socket's file descriptor
type

View File

@@ -7,10 +7,12 @@
# 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
## new ``url`` module.
## Parses & constructs URLs.
{.deprecated.}
import strutils

View File

@@ -25,6 +25,10 @@
##
## **Warning:** The API of this module is unstable, and therefore is subject
## 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"

View File

@@ -7,6 +7,10 @@
# 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
## of sockets. Sockets are buffered by default meaning that data will be
## received in ``BufferSize`` (4000) sized chunks, buffering
@@ -23,9 +27,6 @@
##
## Asynchronous sockets are supported, however a better alternative is to use
## 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.}

View File

@@ -19,14 +19,14 @@ type
{.deprecated: [TUrl: Url, TUri: Uri].}
proc `$`*(url: TUrl): string {.deprecated.} =
## **Deprecated since 0.9.6**: Use ``TUri`` instead.
proc `$`*(url: Url): string {.deprecated.} =
## **Deprecated since 0.9.6**: Use ``Uri`` instead.
return string(url)
proc `/`*(a, b: TUrl): TUrl {.deprecated.} =
proc `/`*(a, b: Url): Url {.deprecated.} =
## 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 bS = $b
if urlS == "": return b
@@ -36,15 +36,15 @@ proc `/`*(a, b: TUrl): TUrl {.deprecated.} =
urlS.add(bS.substr(1))
else:
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.
##
## **Deprecated since 0.9.6**: Use ``TUri`` instead.
## **Deprecated since 0.9.6**: Use ``Uri`` instead.
url = url / a
proc parseAuthority(authority: string, result: var TUri) =
proc parseAuthority(authority: string, result: var Uri) =
var i = 0
var inPort = false
while true:
@@ -65,7 +65,7 @@ proc parseAuthority(authority: string, result: var TUri) =
result.hostname.add(authority[i])
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)
@@ -82,11 +82,11 @@ proc parsePath(uri: string, i: var int, result: var TUri) =
i.inc # Skip '#'
i.inc parseUntil(uri, result.anchor, {}, i)
proc initUri(): TUri =
result = TUri(scheme: "", username: "", password: "", hostname: "", port: "",
proc initUri(): Uri =
result = Uri(scheme: "", username: "", password: "", hostname: "", port: "",
path: "", query: "", anchor: "")
proc parseUri*(uri: string): TUri =
proc parseUri*(uri: string): Uri =
## Parses a URI.
result = initUri()
@@ -113,7 +113,7 @@ proc parseUri*(uri: string): TUri =
var authority = ""
i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
if authority == "":
raise newException(EInvalidValue, "Expected authority got nothing.")
raise newException(ValueError, "Expected authority got nothing.")
parseAuthority(authority, result)
# Path
@@ -150,7 +150,7 @@ proc removeDotSegments(path: string): string =
result = collection.join("/")
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
if base.hostname != "" and base.path == "":
'/' & reference.path
@@ -161,7 +161,7 @@ proc merge(base, reference: TUri): string =
else:
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.
##
## This uses the algorithm specified in
@@ -216,13 +216,13 @@ proc combine*(base: TUri, reference: TUri): TUri =
result.scheme = base.scheme
result.anchor = reference.anchor
proc combine*(uris: varargs[TUri]): TUri =
proc combine*(uris: varargs[Uri]): Uri =
## Combines multiple URIs together.
result = uris[0]
for i in 1 .. <uris.len:
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.
##
## 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(path)
proc `$`*(u: TUri): string =
proc `$`*(u: Uri): string =
## Returns the string representation of the specified URI object.
result = ""
if u.scheme.len > 0:

View File

@@ -53,9 +53,7 @@ proc createServer(port: TPort) {.async.} =
discard server.SocketHandle.listen()
while true:
var client = await accept(server)
asyncCheck readMessages(client)
# TODO: Test: readMessages(disp, await disp.accept(server))
asyncCheck readMessages(await accept(server))
asyncCheck createServer(TPort(10335))
asyncCheck launchSwarm(TPort(10335))

View File

@@ -47,7 +47,7 @@ proc serverAccept(s: PAsyncSocket) =
proc launchSwarm(disp: var PDispatcher, port: TPort, count: int,
buffered = true, useSSL = false) =
for i in 1..count:
var client = AsyncSocket()
var client = asyncSocket()
when defined(ssl):
if useSSL:
ctx1.wrapSocket(client)
@@ -56,7 +56,7 @@ proc launchSwarm(disp: var PDispatcher, port: TPort, count: int,
client.connect("localhost", port)
proc createSwarm(port: TPort, buffered = true, useSSL = false) =
var server = AsyncSocket()
var server = asyncSocket()
when defined(ssl):
if useSSL:
ctx.wrapSocket(server)

View File

@@ -42,14 +42,14 @@ proc swarmConnect(s: PAsyncSocket) =
proc createClient(disp: var PDispatcher, port: TPort,
buffered = true) =
currentClient.inc()
var client = AsyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
var client = asyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
buffered = buffered)
client.handleConnect = swarmConnect
disp.register(client)
client.connect("localhost", port)
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)
server.handleRead = serverRead
disp.register(server)
@@ -75,4 +75,4 @@ while true:
break
assert msgCount == messagesToSend * serverCount * swarmSize
echo(msgCount)
echo(msgCount)

View File

@@ -396,8 +396,8 @@ proc buildNewsRss(c: var TConfigData, destPath: string) =
generateRss(destFilename, parseNewsTitles(srcFilename))
proc buildJS(destPath: string) =
exec("nim js -d:release --out:$1 web/babelpkglist.nim" %
[destPath / "babelpkglist.js"])
exec("nim js -d:release --out:$1 web/nimblepkglist.nim" %
[destPath / "nimblepkglist.js"])
proc buildWebsite(c: var TConfigData) =
const

View File

@@ -41,6 +41,7 @@ proc processContent(content: string) =
dot = if desc.high > 0 and desc[desc.high] in endings: "" else: "."
listItem = li(a(href=pkgWeb, pkg["name"].str), " ", desc & dot)
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:
officialCount.inc
officialList.add listItem & "\n"
@@ -52,14 +53,14 @@ proc processContent(content: string) =
officialPkgListDiv.innerHTML =
p("There are currently " & $officialCount &
" official packages in the Babel package repository.") &
" official packages in the Nimble package repository.") &
ul(officialList)
var unofficialPkgListDiv = document.getElementById("unofficialPkgList")
unofficialPkgListDiv.innerHTML =
p("There are currently " & $unofficialCount &
" unofficial packages in the Babel package repository.") &
" unofficial packages in the Nimble package repository.") &
ul(unofficialList)
proc gotPackageList(apiReply: TData) {.exportc.} =

View File

@@ -6,14 +6,67 @@ News
2014-10-21 Version 0.10.2 released
==================================
This release is the latest release before the release canditates for version
1.0 roll in. Starting with version 0.10.2 the rename of the language to Nim
is officially complete. As the list of language changes is quite long it's
much more work to update the average Nim project than used to be the case.
However there is a new tool, `nimfix <nimfix.html>`_ to help you
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.
This release marks the completion of a very important change to the project:
the official renaming from Nimrod to Nim. Version 0.10.2 contains many language
changes, some of which may break your existing code. For your convenience, we
added a new tool called `nimfix <nimfix.html>`_ that will help you convert your
existing projects so that it works with the latest version of the compiler.
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
-----------------------------------------
@@ -93,7 +146,7 @@ News
statement.
- There is a new tool, `nimfix <nimfix.html>`_ to help you in updating your
code from Nimrod to Nim.
- The compiler's output has been prettified.
Library Additions
-----------------
@@ -103,7 +156,41 @@ News
- ``system.setupForeignThreadGc`` can be used for better interaction with
foreign libraries that create threads and run a Nim callback from these
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!
==============================