Skip to content

cmiles74/bencode

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

54 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Bencode

A Janet library for decoding data in the Bencode format.

Continuous Integration

I read through the source code of several Bencode libraries but I spent the most time with the nREPL/bencode project, I used a lot of their test strings to verify that this implementation was working correctly.

If you find this code useful in any way, please feel free to...

Buy Me A Coffee

Installation

Add the dependency to your project...

(declare-project
  :dependencies ["https://github.com/cmiles74/bencode"])

Usage

This library provides functions for reading and writing data in the bencode format.

Reading

We provide two functions to make it easier to consume data in the Bencode format: read-buffer and read-stream. The easiest case is when you have one a string with one data structure, you may pass the string to read-buffer and get your ben-decoded data.

> (import bencode)
> (bencode/read-buffer "d3:ham4:eggs4:costi5ee")
{:cost 5 :ham @"eggs"}

Here the "buffer" is the string with the bencoded data. We read the first and only item from the buffer and return it.

If you have more than one structure, you will want to wrap a reader around your buffer with the reader function.

> (import bencode)
> (def rdr (bencode/reader "d3:ham4:eggs4:costi5eed3:ham4:eggse"))
@{:buffer "d3:ham4:eggs4:costi5eed3:ham4:eggse" :index 0}
> (bencode/read rdr)
{:cost 5 :ham @"eggs"}
> (bencode/read rdr)
{:ham @"eggs"}
> (bencode/read rdr)
nil

If you are reading data from a stream then clearly read-stream is the function for you. You pass it the stream and it reads the next chunk of data, if no data has yet been written to the stream then it will block until some data is available. You may also create a reader around your stream with reader-stream and then perform successive read operations.

The reader and reader-stream functions returns a table includes the buffer or stream of data and keeps track of what data has been read from the buffer. The read function accepts a reader and returns the next data structure in the buffer.

The read-buffer and read-stream functions are for your convenience, they accept a stream or buffer and then return the next data item from the stream or buffer. Only one item may be read in this way with read-buffer, each call will create a new reader around the same buffer and will return the same data.

The read, read-buffer and read-stream methods accept the following keyword-style options:

  • When we read a map from the buffer, the keys are turned into keywords by default. You can change this behavior by passing a :keyword-dicts false.

  • Newlines between the consecutive values can be ignored by passing :ignore-newlines true.

  • By default returned values are immutable: structs, tuples and strings. To return mutable values: tables, arrays and buffers - pass :return-mutable true.

Writing

We provide two functions you may use to encode Janet data structures into the bencode format. The easiest case is when you have a data structure and would like a buffer with the same data in the bencode format.

When a map is encoded, the keys are encoded as strings.

> (import bencode)
> (def buffer-out (bencode/write {:name "Emily" :job "Student"}))
@"d3:job7:Student4:name5:Emilye"

The write function accepts a buffer and a data structure and returns a buffer with the bencoded data.

> (import bencode)
> (def buffer-out @"")
> (bencode/write {:name "Emily" :job "Student"})
@"d3:job7:Student4:name5:Emilye"

The write-buffer function accepts a buffer and writes the bencoded value into that buffer. In the example below we write two items to the buffer.

> (import bencode)
> (def buffer-out @"")
> (bencode/write-buffer {:name "Emily" :job "Student"})
@"d3:job7:Student4:name5:Emilye"
> (bencode/write-buffer buffer-out {:name "Joanna" :job "Career Advisor"})
@"d3:job7:Student4:name5:Emilyed3:job14:Career Advisor4:name6:Joannae"

If you need to write to a stream, you can always write to a buffer and then write the buffer to the stream. Or you may use the write-stream function.

> (import bencode)
> (def s (net/connect "someserver.com" "8080"))
> (bencode/write-stream s {:name "Emily" :job "Student"})
> (:close s)

These functions also accepts some keyword-style options:

  • By default the conversion of data is lax which means that for keyword or symbol values the type information is lost upon conversion, they are converted to strings. If you need to keep the strict invariant (= str (decode (encode str))), pass :strict-conversion true. This will throw an exception for data that cannot be encoded.

Building

This library uses JPM to manage dependencies, run tests, etc. If you plan on hacking away at this library you will need to get JPM installed. With that out of the way, you may clone the project and pull in the dependencies the project needs (at this time, only the testing library).

$ cd bencode
$ jpm deps

The dependencies will be installed and now you can run the test suite.

$ jpm test

The tests should run quickly and they all should pass. If you have a pull request, please make sure the tests are passing. ;-)


About

A Janet library for the Bencode format

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages