3f31f08c385037060967e212965601472ac04bb6 — Jacob Moody a month ago 841e42f
Adapt srv_test in to an example.
Be a bit more explicit on where to find documentation.
3 files changed, 37 insertions(+), 40 deletions(-)

M fs.go
R srv_test.go => srv_example_test.go
M README.md => README.md +4 -2
@@ 1,4 1,6 @@

Ninep is a go library for writing 9p2000 servers. It is heavily influenced by the design of the plan9
lib9p C library.
Ninep is a go library for writing 9p2000 servers. It is heavily influenced by the design of the plan9 lib9p C library.
The godocs link has some examples and more specific details for library usage.

It is reccomended to have some familiarity with 9p itself. The best resource to learn what the server is responsible for is reading through [section 5 of the manual](http://man.cat-v.org/9front/5/).

M fs.go => fs.go +1 -1
@@ 51,7 51,7 @@ type FS interface {
//See the Srv documentation
type FSMaker func() FS

//NopFS is a filesystem that can simply errors
//NopFS is a filesystem that simply errors
//on each request message. NopFS can be
//embedded to respond to request types the
//server does not plan to support.

R srv_test.go => srv_example_test.go +32 -37
@@ 1,24 1,27 @@
package ninep
package ninep_test

import (


type testfs struct {
//Embed NopFS to cover message types we dont plan
//to support.
type myfs struct {
	i     int
	msg   []byte
	rootD Dir
	fileD Dir
	rootD ninep.Dir
	fileD ninep.Dir

func (e *testfs) Attach(t *Tattach) {
func (e *myfs) Attach(t *ninep.Tattach) {
	e.msg = []byte(fmt.Sprintf("You are lucky number %d\n", e.i))
	e.fileD = Dir{
		Qid:  Qid{1, 0, 0},
	e.fileD = ninep.Dir{
		Qid:  ninep.Qid{1, 0, 0},
		Mode: 0x4,
		Len:  uint64(len(e.msg)),
		Name: "test",

@@ 26,65 29,57 @@ func (e *testfs) Attach(t *Tattach) {
		Gid:  "moody",
		Muid: "moody",
	e.rootD = Dir{
		Qid:  Qid{0, 0, QTDir},
	e.rootD = ninep.Dir{
		Qid:  ninep.Qid{0, 0, ninep.QTDir},
		Name: "/",
		Mode: DMDir | 0777,
		Mode: ninep.DMDir | 0777,
		Uid:  "moody",
		Gid:  "moody",
		Muid: "moody",
	t.Respond(&Rattach{Qid: Qid{0, 0, 0x80}}, nil)
	t.Respond(&ninep.Rattach{Qid: e.rootD.Qid}, nil)

func (e *testfs) Walk(cur *Qid, next string) *Qid {
func (e *myfs) Walk(cur *ninep.Qid, next string) *ninep.Qid {
	if cur.Path == 0 && next == "test" {
		return &Qid{1, 0, 0}
		return &e.fileD.Qid
	return nil

func (e *testfs) Open(t *Topen, q *Qid) {
	t.Respond(&Ropen{Qid: *q, Iounit: 8192}, nil)
func (e *myfs) Open(t *ninep.Topen, q *ninep.Qid) {
	t.Respond(&ninep.Ropen{Qid: *q, Iounit: 8192}, nil)

var errNoFile = errors.New("no such file or directory")

func (e *testfs) Read(t *Tread, q *Qid) {
func (e *myfs) Read(t *ninep.Tread, q *ninep.Qid) {
	switch q.Path {
	case 0:
		ReadDir(t, []Dir{e.fileD})
		ninep.ReadDir(t, []ninep.Dir{e.fileD})
	case 1:
		ReadBuf(t, e.msg)
		ninep.ReadBuf(t, e.msg)
		t.Respond(nil, errNoFile)

func (e *testfs) Stat(t *Tstat, q *Qid) {
func (e *myfs) Stat(t *ninep.Tstat, q *ninep.Qid) {
	switch q.Path {
	case 0:
		t.Respond(&Rstat{Dir: e.rootD}, nil)
		t.Respond(&ninep.Rstat{Dir: e.rootD}, nil)
	case 1:
		t.Respond(&Rstat{Dir: e.fileD}, nil)
		t.Respond(&ninep.Rstat{Dir: e.fileD}, nil)
		t.Respond(nil, errNoFile)

//works but needs to be made automatic
func TestSrv(t *testing.T) {
func Example() {
	i := 0
	srv := NewSrv(func() FS { i++; return &testfs{i: i} })
	//Create a new srv, where each new session is given an instance
	//of myfs. For each session i will be incremented.
	srv := ninep.NewSrv(func() ninep.FS { i++; return &myfs{i: i} })
	srv.Chatty9P = true
	l, err := net.Listen("tcp", ":9999")
	if err != nil {
	c, err := l.Accept()
	if err != nil {
	go srv.writeLoop(c)