<commit_before>package core

import (
	"reflect"
	"sort"
	"strings"
	"time"
)

const (
	POSTGRES = "postgres"
	SQLITE   = "sqlite3"
	MYSQL    = "mysql"
	MSSQL    = "mssql"
	ORACLE   = "oracle"
)

// xorm SQL types
type SQLType struct {
	Name           string
	DefaultLength  int
	DefaultLength2 int
}

const (
	UNKNOW_TYPE = iota
	TEXT_TYPE
	BLOB_TYPE
	TIME_TYPE
	NUMERIC_TYPE
)

func (s *SQLType) IsType(st int) bool {
	if t, ok := SqlTypes[s.Name]; ok && t == st {
		return true
	}
	return false
}

func (s *SQLType) IsText() bool {
	return s.IsType(TEXT_TYPE)
}

func (s *SQLType) IsBlob() bool {
	return s.IsType(BLOB_TYPE)
}

func (s *SQLType) IsTime() bool {
	return s.IsType(TIME_TYPE)
}

func (s *SQLType) IsNumeric() bool {
	return s.IsType(NUMERIC_TYPE)
}

func (s *SQLType) IsJson() bool {
	return s.Name == Json || s.Name == Jsonb
}

var (
	Bit       = "BIT"
	TinyInt   = "TINYINT"
	SmallInt  = "SMALLINT"
	MediumInt = "MEDIUMINT"
	Int       = "INT"
	Integer   = "INTEGER"
	BigInt    = "BIGINT"

	Enum = "ENUM"
	Set  = "SET"

	Char       = "CHAR"
	Varchar    = "VARCHAR"
	NVarchar   = "NVARCHAR"
	TinyText   = "TINYTEXT"
	Text       = "TEXT"
	Clob       = "CLOB"
	MediumText = "MEDIUMTEXT"
	LongText   = "LONGTEXT"
	Uuid       = "UUID"

	Date       = "DATE"
	DateTime   = "DATETIME"
	Time       = "TIME"
	TimeStamp  = "TIMESTAMP"
	TimeStampz = "TIMESTAMPZ"

	Decimal = "DECIMAL"
	Numeric = "NUMERIC"

	Real   = "REAL"
	Float  = "FLOAT"
	Double = "DOUBLE"

	Binary     = "BINARY"
	VarBinary  = "VARBINARY"
	TinyBlob   = "TINYBLOB"
	Blob       = "BLOB"
	MediumBlob = "MEDIUMBLOB"
	LongBlob   = "LONGBLOB"
	Bytea      = "BYTEA"

	Bool = "BOOL"

	Serial    = "SERIAL"
	BigSerial = "BIGSERIAL"

	Json  = "JSON"
	Jsonb = "JSONB"

	SqlTypes = map[string]int{
		Bit:       NUMERIC_TYPE,
		TinyInt:   NUMERIC_TYPE,
		SmallInt:  NUMERIC_TYPE,
		MediumInt: NUMERIC_TYPE,
		Int:       NUMERIC_TYPE,
		Integer:   NUMERIC_TYPE,
		BigInt:    NUMERIC_TYPE,

		Enum:  TEXT_TYPE,
		Set:   TEXT_TYPE,
		Json:  TEXT_TYPE,
		Jsonb: TEXT_TYPE,

		Char:       TEXT_TYPE,
		Varchar:    TEXT_TYPE,
		NVarchar:   TEXT_TYPE,
		TinyText:   TEXT_TYPE,
		Text:       TEXT_TYPE,
		MediumText: TEXT_TYPE,
		LongText:   TEXT_TYPE,
		Uuid:       TEXT_TYPE,
		Clob:       TEXT_TYPE,

		Date:       TIME_TYPE,
		DateTime:   TIME_TYPE,
		Time:       TIME_TYPE,
		TimeStamp:  TIME_TYPE,
		TimeStampz: TIME_TYPE,

		Decimal: NUMERIC_TYPE,
		Numeric: NUMERIC_TYPE,
		Real:    NUMERIC_TYPE,
		Float:   NUMERIC_TYPE,
		Double:  NUMERIC_TYPE,

		Binary:    BLOB_TYPE,
		VarBinary: BLOB_TYPE,

		TinyBlob:   BLOB_TYPE,
		Blob:       BLOB_TYPE,
		MediumBlob: BLOB_TYPE,
		LongBlob:   BLOB_TYPE,
		Bytea:      BLOB_TYPE,

		Bool: NUMERIC_TYPE,

		Serial:    NUMERIC_TYPE,
		BigSerial: NUMERIC_TYPE,
	}

	intTypes  = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
	uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
)

// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparision
var (
	c_EMPTY_STRING       string
	c_BOOL_DEFAULT       bool
	c_BYTE_DEFAULT       byte
	c_COMPLEX64_DEFAULT  complex64
	c_COMPLEX128_DEFAULT complex128
	c_FLOAT32_DEFAULT    float32
	c_FLOAT64_DEFAULT    float64
	c_INT64_DEFAULT      int64
	c_UINT64_DEFAULT     uint64
	c_INT32_DEFAULT      int32
	c_UINT32_DEFAULT     uint32
	c_INT16_DEFAULT      int16
	c_UINT16_DEFAULT     uint16
	c_INT8_DEFAULT       int8
	c_UINT8_DEFAULT      uint8
	c_INT_DEFAULT        int
	c_UINT_DEFAULT       uint
	c_TIME_DEFAULT       time.Time
)

var (
	IntType   = reflect.TypeOf(c_INT_DEFAULT)
	Int8Type  = reflect.TypeOf(c_INT8_DEFAULT)
	Int16Type = reflect.TypeOf(c_INT16_DEFAULT)
	Int32Type = reflect.TypeOf(c_INT32_DEFAULT)
	Int64Type = reflect.TypeOf(c_INT64_DEFAULT)

	UintType   = reflect.TypeOf(c_UINT_DEFAULT)
	Uint8Type  = reflect.TypeOf(c_UINT8_DEFAULT)
	Uint16Type = reflect.TypeOf(c_UINT16_DEFAULT)
	Uint32Type = reflect.TypeOf(c_UINT32_DEFAULT)
	Uint64Type = reflect.TypeOf(c_UINT64_DEFAULT)

	Float32Type = reflect.TypeOf(c_FLOAT32_DEFAULT)
	Float64Type = reflect.TypeOf(c_FLOAT64_DEFAULT)

	Complex64Type  = reflect.TypeOf(c_COMPLEX64_DEFAULT)
	Complex128Type = reflect.TypeOf(c_COMPLEX128_DEFAULT)

	StringType = reflect.TypeOf(c_EMPTY_STRING)
	BoolType   = reflect.TypeOf(c_BOOL_DEFAULT)
	ByteType   = reflect.TypeOf(c_BYTE_DEFAULT)
	BytesType  = reflect.SliceOf(ByteType)

	TimeType = reflect.TypeOf(c_TIME_DEFAULT)
)

var (
	PtrIntType   = reflect.PtrTo(IntType)
	PtrInt8Type  = reflect.PtrTo(Int8Type)
	PtrInt16Type = reflect.PtrTo(Int16Type)
	PtrInt32Type = reflect.PtrTo(Int32Type)
	PtrInt64Type = reflect.PtrTo(Int64Type)

	PtrUintType   = reflect.PtrTo(UintType)
	PtrUint8Type  = reflect.PtrTo(Uint8Type)
	PtrUint16Type = reflect.PtrTo(Uint16Type)
	PtrUint32Type = reflect.PtrTo(Uint32Type)
	PtrUint64Type = reflect.PtrTo(Uint64Type)

	PtrFloat32Type = reflect.PtrTo(Float32Type)
	PtrFloat64Type = reflect.PtrTo(Float64Type)

	PtrComplex64Type  = reflect.PtrTo(Complex64Type)
	PtrComplex128Type = reflect.PtrTo(Complex128Type)

	PtrStringType = reflect.PtrTo(StringType)
	PtrBoolType   = reflect.PtrTo(BoolType)
	PtrByteType   = reflect.PtrTo(ByteType)

	PtrTimeType = reflect.PtrTo(TimeType)
)

// Type2SQLType generate SQLType acorrding Go's type
func Type2SQLType(t reflect.Type) (st SQLType) {
	switch k := t.Kind(); k {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		st = SQLType{Int, 0, 0}
	case reflect.Int64, reflect.Uint64:
		st = SQLType{BigInt, 0, 0}
	case reflect.Float32:
		st = SQLType{Float, 0, 0}
	case reflect.Float64:
		st = SQLType{Double, 0, 0}
	case reflect.Complex64, reflect.Complex128:
		st = SQLType{Varchar, 64, 0}
	case reflect.Array, reflect.Slice, reflect.Map:
		if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
			st = SQLType{Blob, 0, 0}
		} else {
			st = SQLType{Text, 0, 0}
		}
	case reflect.Bool:
		st = SQLType{Bool, 0, 0}
	case reflect.String:
		st = SQLType{Varchar, 255, 0}
	case reflect.Struct:
		if t.ConvertibleTo(TimeType) {
			st = SQLType{DateTime, 0, 0}
		} else {
			// TODO need to handle association struct
			st = SQLType{Text, 0, 0}
		}
	case reflect.Ptr:
		st = Type2SQLType(t.Elem())
	default:
		st = SQLType{Text, 0, 0}
	}
	return
}

// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
	name := strings.ToUpper(st.Name)
	switch name {
	case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
		return reflect.TypeOf(1)
	case BigInt, BigSerial:
		return reflect.TypeOf(int64(1))
	case Float, Real:
		return reflect.TypeOf(float32(1))
	case Double:
		return reflect.TypeOf(float64(1))
	case Char, Varchar, NVarchar, TinyText, Text, MediumText, LongText, Enum, Set, Uuid, Clob:
		return reflect.TypeOf("")
	case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary:
		return reflect.TypeOf([]byte{})
	case Bool:
		return reflect.TypeOf(true)
	case DateTime, Date, Time, TimeStamp, TimeStampz:
		return reflect.TypeOf(c_TIME_DEFAULT)
	case Decimal, Numeric:
		return reflect.TypeOf("")
	default:
		return reflect.TypeOf("")
	}
}
<commit_msg>correct spelling mistake<commit_after>package core

import (
	"reflect"
	"sort"
	"strings"
	"time"
)

const (
	POSTGRES = "postgres"
	SQLITE   = "sqlite3"
	MYSQL    = "mysql"
	MSSQL    = "mssql"
	ORACLE   = "oracle"
)

// xorm SQL types
type SQLType struct {
	Name           string
	DefaultLength  int
	DefaultLength2 int
}

const (
	UNKNOW_TYPE = iota
	TEXT_TYPE
	BLOB_TYPE
	TIME_TYPE
	NUMERIC_TYPE
)

func (s *SQLType) IsType(st int) bool {
	if t, ok := SqlTypes[s.Name]; ok && t == st {
		return true
	}
	return false
}

func (s *SQLType) IsText() bool {
	return s.IsType(TEXT_TYPE)
}

func (s *SQLType) IsBlob() bool {
	return s.IsType(BLOB_TYPE)
}

func (s *SQLType) IsTime() bool {
	return s.IsType(TIME_TYPE)
}

func (s *SQLType) IsNumeric() bool {
	return s.IsType(NUMERIC_TYPE)
}

func (s *SQLType) IsJson() bool {
	return s.Name == Json || s.Name == Jsonb
}

var (
	Bit       = "BIT"
	TinyInt   = "TINYINT"
	SmallInt  = "SMALLINT"
	MediumInt = "MEDIUMINT"
	Int       = "INT"
	Integer   = "INTEGER"
	BigInt    = "BIGINT"

	Enum = "ENUM"
	Set  = "SET"

	Char       = "CHAR"
	Varchar    = "VARCHAR"
	NVarchar   = "NVARCHAR"
	TinyText   = "TINYTEXT"
	Text       = "TEXT"
	Clob       = "CLOB"
	MediumText = "MEDIUMTEXT"
	LongText   = "LONGTEXT"
	Uuid       = "UUID"

	Date       = "DATE"
	DateTime   = "DATETIME"
	Time       = "TIME"
	TimeStamp  = "TIMESTAMP"
	TimeStampz = "TIMESTAMPZ"

	Decimal = "DECIMAL"
	Numeric = "NUMERIC"

	Real   = "REAL"
	Float  = "FLOAT"
	Double = "DOUBLE"

	Binary     = "BINARY"
	VarBinary  = "VARBINARY"
	TinyBlob   = "TINYBLOB"
	Blob       = "BLOB"
	MediumBlob = "MEDIUMBLOB"
	LongBlob   = "LONGBLOB"
	Bytea      = "BYTEA"

	Bool = "BOOL"

	Serial    = "SERIAL"
	BigSerial = "BIGSERIAL"

	Json  = "JSON"
	Jsonb = "JSONB"

	SqlTypes = map[string]int{
		Bit:       NUMERIC_TYPE,
		TinyInt:   NUMERIC_TYPE,
		SmallInt:  NUMERIC_TYPE,
		MediumInt: NUMERIC_TYPE,
		Int:       NUMERIC_TYPE,
		Integer:   NUMERIC_TYPE,
		BigInt:    NUMERIC_TYPE,

		Enum:  TEXT_TYPE,
		Set:   TEXT_TYPE,
		Json:  TEXT_TYPE,
		Jsonb: TEXT_TYPE,

		Char:       TEXT_TYPE,
		Varchar:    TEXT_TYPE,
		NVarchar:   TEXT_TYPE,
		TinyText:   TEXT_TYPE,
		Text:       TEXT_TYPE,
		MediumText: TEXT_TYPE,
		LongText:   TEXT_TYPE,
		Uuid:       TEXT_TYPE,
		Clob:       TEXT_TYPE,

		Date:       TIME_TYPE,
		DateTime:   TIME_TYPE,
		Time:       TIME_TYPE,
		TimeStamp:  TIME_TYPE,
		TimeStampz: TIME_TYPE,

		Decimal: NUMERIC_TYPE,
		Numeric: NUMERIC_TYPE,
		Real:    NUMERIC_TYPE,
		Float:   NUMERIC_TYPE,
		Double:  NUMERIC_TYPE,

		Binary:    BLOB_TYPE,
		VarBinary: BLOB_TYPE,

		TinyBlob:   BLOB_TYPE,
		Blob:       BLOB_TYPE,
		MediumBlob: BLOB_TYPE,
		LongBlob:   BLOB_TYPE,
		Bytea:      BLOB_TYPE,

		Bool: NUMERIC_TYPE,

		Serial:    NUMERIC_TYPE,
		BigSerial: NUMERIC_TYPE,
	}

	intTypes  = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
	uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
)

// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparison
var (
	c_EMPTY_STRING       string
	c_BOOL_DEFAULT       bool
	c_BYTE_DEFAULT       byte
	c_COMPLEX64_DEFAULT  complex64
	c_COMPLEX128_DEFAULT complex128
	c_FLOAT32_DEFAULT    float32
	c_FLOAT64_DEFAULT    float64
	c_INT64_DEFAULT      int64
	c_UINT64_DEFAULT     uint64
	c_INT32_DEFAULT      int32
	c_UINT32_DEFAULT     uint32
	c_INT16_DEFAULT      int16
	c_UINT16_DEFAULT     uint16
	c_INT8_DEFAULT       int8
	c_UINT8_DEFAULT      uint8
	c_INT_DEFAULT        int
	c_UINT_DEFAULT       uint
	c_TIME_DEFAULT       time.Time
)

var (
	IntType   = reflect.TypeOf(c_INT_DEFAULT)
	Int8Type  = reflect.TypeOf(c_INT8_DEFAULT)
	Int16Type = reflect.TypeOf(c_INT16_DEFAULT)
	Int32Type = reflect.TypeOf(c_INT32_DEFAULT)
	Int64Type = reflect.TypeOf(c_INT64_DEFAULT)

	UintType   = reflect.TypeOf(c_UINT_DEFAULT)
	Uint8Type  = reflect.TypeOf(c_UINT8_DEFAULT)
	Uint16Type = reflect.TypeOf(c_UINT16_DEFAULT)
	Uint32Type = reflect.TypeOf(c_UINT32_DEFAULT)
	Uint64Type = reflect.TypeOf(c_UINT64_DEFAULT)

	Float32Type = reflect.TypeOf(c_FLOAT32_DEFAULT)
	Float64Type = reflect.TypeOf(c_FLOAT64_DEFAULT)

	Complex64Type  = reflect.TypeOf(c_COMPLEX64_DEFAULT)
	Complex128Type = reflect.TypeOf(c_COMPLEX128_DEFAULT)

	StringType = reflect.TypeOf(c_EMPTY_STRING)
	BoolType   = reflect.TypeOf(c_BOOL_DEFAULT)
	ByteType   = reflect.TypeOf(c_BYTE_DEFAULT)
	BytesType  = reflect.SliceOf(ByteType)

	TimeType = reflect.TypeOf(c_TIME_DEFAULT)
)

var (
	PtrIntType   = reflect.PtrTo(IntType)
	PtrInt8Type  = reflect.PtrTo(Int8Type)
	PtrInt16Type = reflect.PtrTo(Int16Type)
	PtrInt32Type = reflect.PtrTo(Int32Type)
	PtrInt64Type = reflect.PtrTo(Int64Type)

	PtrUintType   = reflect.PtrTo(UintType)
	PtrUint8Type  = reflect.PtrTo(Uint8Type)
	PtrUint16Type = reflect.PtrTo(Uint16Type)
	PtrUint32Type = reflect.PtrTo(Uint32Type)
	PtrUint64Type = reflect.PtrTo(Uint64Type)

	PtrFloat32Type = reflect.PtrTo(Float32Type)
	PtrFloat64Type = reflect.PtrTo(Float64Type)

	PtrComplex64Type  = reflect.PtrTo(Complex64Type)
	PtrComplex128Type = reflect.PtrTo(Complex128Type)

	PtrStringType = reflect.PtrTo(StringType)
	PtrBoolType   = reflect.PtrTo(BoolType)
	PtrByteType   = reflect.PtrTo(ByteType)

	PtrTimeType = reflect.PtrTo(TimeType)
)

// Type2SQLType generate SQLType acorrding Go's type
func Type2SQLType(t reflect.Type) (st SQLType) {
	switch k := t.Kind(); k {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		st = SQLType{Int, 0, 0}
	case reflect.Int64, reflect.Uint64:
		st = SQLType{BigInt, 0, 0}
	case reflect.Float32:
		st = SQLType{Float, 0, 0}
	case reflect.Float64:
		st = SQLType{Double, 0, 0}
	case reflect.Complex64, reflect.Complex128:
		st = SQLType{Varchar, 64, 0}
	case reflect.Array, reflect.Slice, reflect.Map:
		if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
			st = SQLType{Blob, 0, 0}
		} else {
			st = SQLType{Text, 0, 0}
		}
	case reflect.Bool:
		st = SQLType{Bool, 0, 0}
	case reflect.String:
		st = SQLType{Varchar, 255, 0}
	case reflect.Struct:
		if t.ConvertibleTo(TimeType) {
			st = SQLType{DateTime, 0, 0}
		} else {
			// TODO need to handle association struct
			st = SQLType{Text, 0, 0}
		}
	case reflect.Ptr:
		st = Type2SQLType(t.Elem())
	default:
		st = SQLType{Text, 0, 0}
	}
	return
}

// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
	name := strings.ToUpper(st.Name)
	switch name {
	case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
		return reflect.TypeOf(1)
	case BigInt, BigSerial:
		return reflect.TypeOf(int64(1))
	case Float, Real:
		return reflect.TypeOf(float32(1))
	case Double:
		return reflect.TypeOf(float64(1))
	case Char, Varchar, NVarchar, TinyText, Text, MediumText, LongText, Enum, Set, Uuid, Clob:
		return reflect.TypeOf("")
	case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary:
		return reflect.TypeOf([]byte{})
	case Bool:
		return reflect.TypeOf(true)
	case DateTime, Date, Time, TimeStamp, TimeStampz:
		return reflect.TypeOf(c_TIME_DEFAULT)
	case Decimal, Numeric:
		return reflect.TypeOf("")
	default:
		return reflect.TypeOf("")
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fuse

import (
	"errors"
	"fmt"
	"log"
	"path"
	"runtime"
	"sync"

	"golang.org/x/net/context"

	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/fuse/internal/fusekernel"
	"github.com/jacobsa/fuse/internal/fuseshim"
)

// A connection to the fuse kernel process.
type Connection struct {
	debugLogger *log.Logger
	errorLogger *log.Logger
	wrapped     *fuseshim.Conn

	// The context from which all op contexts inherit.
	parentCtx context.Context

	// For logging purposes only.
	nextOpID uint32

	mu sync.Mutex

	// A map from fuse "unique" request ID (*not* the op ID for logging used
	// above) to a function that cancel's its associated context.
	//
	// GUARDED_BY(mu)
	cancelFuncs map[uint64]func()
}

// Responsibility for closing the wrapped connection is transferred to the
// result. You must call c.close() eventually.
//
// The loggers may be nil.
func newConnection(
	parentCtx context.Context,
	debugLogger *log.Logger,
	errorLogger *log.Logger,
	wrapped *fuseshim.Conn) (c *Connection, err error) {
	c = &Connection{
		debugLogger: debugLogger,
		errorLogger: errorLogger,
		wrapped:     wrapped,
		parentCtx:   parentCtx,
		cancelFuncs: make(map[uint64]func()),
	}

	return
}

// Log information for an operation with the given ID. calldepth is the depth
// to use when recovering file:line information with runtime.Caller.
func (c *Connection) debugLog(
	opID uint32,
	calldepth int,
	format string,
	v ...interface{}) {
	if c.debugLogger == nil {
		return
	}

	// Get file:line info.
	var file string
	var line int
	var ok bool

	_, file, line, ok = runtime.Caller(calldepth)
	if !ok {
		file = "???"
	}

	fileLine := fmt.Sprintf("%v:%v", path.Base(file), line)

	// Format the actual message to be printed.
	msg := fmt.Sprintf(
		"Op 0x%08x %24s] %v",
		opID,
		fileLine,
		fmt.Sprintf(format, v...))

	// Print it.
	c.debugLogger.Println(msg)
}

// LOCKS_EXCLUDED(c.mu)
func (c *Connection) recordCancelFunc(
	fuseID uint64,
	f func()) {
	c.mu.Lock()
	defer c.mu.Unlock()

	if _, ok := c.cancelFuncs[fuseID]; ok {
		panic(fmt.Sprintf("Already have cancel func for request %v", fuseID))
	}

	c.cancelFuncs[fuseID] = f
}

// Set up state for an op that is about to be returned to the user, given its
// underlying fuse opcode and request ID.
//
// Return a context that should be used for the op.
//
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) beginOp(
	opCode uint32,
	fuseID uint64) (ctx context.Context) {
	// Start with the parent context.
	ctx = c.parentCtx

	// Set up a cancellation function.
	//
	// Special case: On Darwin, osxfuse aggressively reuses "unique" request IDs.
	// This matters for Forget requests, which have no reply associated and
	// therefore have IDs that are immediately eligible for reuse. For these, we
	// should not record any state keyed on their ID.
	//
	// Cf. https://github.com/osxfuse/osxfuse/issues/208
	if opCode != fusekernel.OpForget {
		var cancel func()
		ctx, cancel = context.WithCancel(ctx)
		c.recordCancelFunc(fuseID, cancel)
	}

	return
}

// Clean up all state associated with an op to which the user has responded,
// given its underlying fuse opcode and request ID. This must be called before
// a response is sent to the kernel, to avoid a race where the request's ID
// might be reused by osxfuse.
//
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) finishOp(
	opCode uint32,
	fuseID uint64) {
	c.mu.Lock()
	defer c.mu.Unlock()

	// Even though the op is finished, context.WithCancel requires us to arrange
	// for the cancellation function to be invoked. We also must remove it from
	// our map.
	//
	// Special case: we don't do this for Forget requests. See the note in
	// beginOp above.
	if opCode != fusekernel.OpForget {
		cancel, ok := c.cancelFuncs[fuseID]
		if !ok {
			panic(fmt.Sprintf("Unknown request ID in finishOp: %v", fuseID))
		}

		cancel()
		delete(c.cancelFuncs, fuseID)
	}
}

// LOCKS_EXCLUDED(c.mu)
func (c *Connection) handleInterrupt(fuseID uint64) {
	c.mu.Lock()
	defer c.mu.Unlock()

	// NOTE(jacobsa): fuse.txt in the Linux kernel documentation
	// (https://goo.gl/H55Dnr) defines the kernel <-> userspace protocol for
	// interrupts.
	//
	// In particular, my reading of it is that an interrupt request cannot be
	// delivered to userspace before the original request. The part about the
	// race and EAGAIN appears to be aimed at userspace programs that
	// concurrently process requests (cf. http://goo.gl/BES2rs).
	//
	// So in this method if we can't find the ID to be interrupted, it means that
	// the request has already been replied to.
	//
	// Cf. https://github.com/osxfuse/osxfuse/issues/208
	// Cf. http://comments.gmane.org/gmane.comp.file-systems.fuse.devel/14675
	cancel, ok := c.cancelFuncs[fuseID]
	if !ok {
		return
	}

	cancel()
}

// Read the next op from the kernel process. Return io.EOF if the kernel has
// closed the connection.
//
// This function delivers ops in exactly the order they are received from
// /dev/fuse. It must not be called multiple times concurrently.
//
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) ReadOp() (op fuseops.Op, err error) {
	// Keep going until we find a request we know how to convert.
	for {
		// Read the next message from the fuseshim connection.
		var m *fuseshim.Message
		m, err = c.wrapped.ReadMessage()
		if err != nil {
			return
		}

		// Choose an ID for this operation for the purposes of logging.
		opID := c.nextOpID
		c.nextOpID++

		// Set up op dependencies.
		opCtx := c.beginOp(m.Hdr.Opcode, m.Hdr.Unique)

		var debugLogForOp func(int, string, ...interface{})
		if c.debugLogger != nil {
			debugLogForOp = func(calldepth int, format string, v ...interface{}) {
				c.debugLog(opID, calldepth+1, format, v...)
			}
		}

		sendReply := func(
			fuseID uint64,
			msg []byte,
			opErr error) (err error) {
			// TODO(jacobsa): Turn this into a method and maybe kill the fuseID
			// parameter.
			//
			// TODO(jacobsa): Don't forget to destroy the message.
			err = errors.New("TODO")
			return
		}

		// Convert the message to an Op.
		op, err = fuseops.Convert(
			opCtx,
			m,
			c.wrapped.Protocol(),
			debugLogForOp,
			c.errorLogger,
			sendReply)

		if err != nil {
			err = fmt.Errorf("fuseops.Convert: %v", err)
			return
		}

		// Log the receipt of the operation.
		c.debugLog(opID, 1, "<- %v", op)

		// Special case: responding to statfs is required to make mounting work on
		// OS X. We don't currently expose the capability for the file system to
		// intercept this.
		if statfsReq, ok := bfReq.(*fuseshim.StatfsRequest); ok {
			c.debugLog(opID, 1, "-> (Statfs) OK")
			statfsReq.Respond(&fuseshim.StatfsResponse{})
			continue
		}

		// Special case: handle interrupt requests.
		if interruptReq, ok := bfReq.(*fuseshim.InterruptRequest); ok {
			c.handleInterrupt(interruptReq)
			continue
		}

		return
	}
}

func (c *Connection) waitForReady() (err error) {
	<-c.wrapped.Ready
	err = c.wrapped.MountError
	return
}

// Close the connection. Must not be called until operations that were read
// from the connection have been responded to.
func (c *Connection) close() (err error) {
	err = c.wrapped.Close()
	return
}
<commit_msg>Fixed statfs and interrupt.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fuse

import (
	"errors"
	"fmt"
	"log"
	"path"
	"runtime"
	"sync"

	"golang.org/x/net/context"

	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/fuse/internal/fusekernel"
	"github.com/jacobsa/fuse/internal/fuseshim"
)

// A connection to the fuse kernel process.
type Connection struct {
	debugLogger *log.Logger
	errorLogger *log.Logger
	wrapped     *fuseshim.Conn

	// The context from which all op contexts inherit.
	parentCtx context.Context

	// For logging purposes only.
	nextOpID uint32

	mu sync.Mutex

	// A map from fuse "unique" request ID (*not* the op ID for logging used
	// above) to a function that cancel's its associated context.
	//
	// GUARDED_BY(mu)
	cancelFuncs map[uint64]func()
}

// Responsibility for closing the wrapped connection is transferred to the
// result. You must call c.close() eventually.
//
// The loggers may be nil.
func newConnection(
	parentCtx context.Context,
	debugLogger *log.Logger,
	errorLogger *log.Logger,
	wrapped *fuseshim.Conn) (c *Connection, err error) {
	c = &Connection{
		debugLogger: debugLogger,
		errorLogger: errorLogger,
		wrapped:     wrapped,
		parentCtx:   parentCtx,
		cancelFuncs: make(map[uint64]func()),
	}

	return
}

// Log information for an operation with the given ID. calldepth is the depth
// to use when recovering file:line information with runtime.Caller.
func (c *Connection) debugLog(
	opID uint32,
	calldepth int,
	format string,
	v ...interface{}) {
	if c.debugLogger == nil {
		return
	}

	// Get file:line info.
	var file string
	var line int
	var ok bool

	_, file, line, ok = runtime.Caller(calldepth)
	if !ok {
		file = "???"
	}

	fileLine := fmt.Sprintf("%v:%v", path.Base(file), line)

	// Format the actual message to be printed.
	msg := fmt.Sprintf(
		"Op 0x%08x %24s] %v",
		opID,
		fileLine,
		fmt.Sprintf(format, v...))

	// Print it.
	c.debugLogger.Println(msg)
}

// LOCKS_EXCLUDED(c.mu)
func (c *Connection) recordCancelFunc(
	fuseID uint64,
	f func()) {
	c.mu.Lock()
	defer c.mu.Unlock()

	if _, ok := c.cancelFuncs[fuseID]; ok {
		panic(fmt.Sprintf("Already have cancel func for request %v", fuseID))
	}

	c.cancelFuncs[fuseID] = f
}

// Set up state for an op that is about to be returned to the user, given its
// underlying fuse opcode and request ID.
//
// Return a context that should be used for the op.
//
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) beginOp(
	opCode uint32,
	fuseID uint64) (ctx context.Context) {
	// Start with the parent context.
	ctx = c.parentCtx

	// Set up a cancellation function.
	//
	// Special case: On Darwin, osxfuse aggressively reuses "unique" request IDs.
	// This matters for Forget requests, which have no reply associated and
	// therefore have IDs that are immediately eligible for reuse. For these, we
	// should not record any state keyed on their ID.
	//
	// Cf. https://github.com/osxfuse/osxfuse/issues/208
	if opCode != fusekernel.OpForget {
		var cancel func()
		ctx, cancel = context.WithCancel(ctx)
		c.recordCancelFunc(fuseID, cancel)
	}

	return
}

// Clean up all state associated with an op to which the user has responded,
// given its underlying fuse opcode and request ID. This must be called before
// a response is sent to the kernel, to avoid a race where the request's ID
// might be reused by osxfuse.
//
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) finishOp(
	opCode uint32,
	fuseID uint64) {
	c.mu.Lock()
	defer c.mu.Unlock()

	// Even though the op is finished, context.WithCancel requires us to arrange
	// for the cancellation function to be invoked. We also must remove it from
	// our map.
	//
	// Special case: we don't do this for Forget requests. See the note in
	// beginOp above.
	if opCode != fusekernel.OpForget {
		cancel, ok := c.cancelFuncs[fuseID]
		if !ok {
			panic(fmt.Sprintf("Unknown request ID in finishOp: %v", fuseID))
		}

		cancel()
		delete(c.cancelFuncs, fuseID)
	}
}

// LOCKS_EXCLUDED(c.mu)
func (c *Connection) handleInterrupt(fuseID uint64) {
	c.mu.Lock()
	defer c.mu.Unlock()

	// NOTE(jacobsa): fuse.txt in the Linux kernel documentation
	// (https://goo.gl/H55Dnr) defines the kernel <-> userspace protocol for
	// interrupts.
	//
	// In particular, my reading of it is that an interrupt request cannot be
	// delivered to userspace before the original request. The part about the
	// race and EAGAIN appears to be aimed at userspace programs that
	// concurrently process requests (cf. http://goo.gl/BES2rs).
	//
	// So in this method if we can't find the ID to be interrupted, it means that
	// the request has already been replied to.
	//
	// Cf. https://github.com/osxfuse/osxfuse/issues/208
	// Cf. http://comments.gmane.org/gmane.comp.file-systems.fuse.devel/14675
	cancel, ok := c.cancelFuncs[fuseID]
	if !ok {
		return
	}

	cancel()
}

// Read the next op from the kernel process. Return io.EOF if the kernel has
// closed the connection.
//
// This function delivers ops in exactly the order they are received from
// /dev/fuse. It must not be called multiple times concurrently.
//
// LOCKS_EXCLUDED(c.mu)
func (c *Connection) ReadOp() (op fuseops.Op, err error) {
	// Keep going until we find a request we know how to convert.
	for {
		// Read the next message from the fuseshim connection.
		var m *fuseshim.Message
		m, err = c.wrapped.ReadMessage()
		if err != nil {
			return
		}

		// Choose an ID for this operation for the purposes of logging.
		opID := c.nextOpID
		c.nextOpID++

		// Set up op dependencies.
		opCtx := c.beginOp(m.Hdr.Opcode, m.Hdr.Unique)

		var debugLogForOp func(int, string, ...interface{})
		if c.debugLogger != nil {
			debugLogForOp = func(calldepth int, format string, v ...interface{}) {
				c.debugLog(opID, calldepth+1, format, v...)
			}
		}

		sendReply := func(
			fuseID uint64,
			msg []byte,
			opErr error) (err error) {
			// TODO(jacobsa): Turn this into a method and maybe kill the fuseID
			// parameter.
			//
			// TODO(jacobsa): Don't forget to destroy the message.
			err = errors.New("TODO")
			return
		}

		// Convert the message to an Op.
		op, err = fuseops.Convert(
			opCtx,
			m,
			c.wrapped.Protocol(),
			debugLogForOp,
			c.errorLogger,
			sendReply)

		if err != nil {
			err = fmt.Errorf("fuseops.Convert: %v", err)
			return
		}

		// Log the receipt of the operation.
		c.debugLog(opID, 1, "<- %v", op)

		// Special case: responding to statfs is required to make mounting work on
		// OS X. We don't currently expose the capability for the file system to
		// intercept this.
		if _, ok := op.(*fuseops.InternalStatFSOp); ok {
			op.Respond(nil)
			continue
		}

		// Special case: handle interrupt requests.
		if interruptOp, ok := op.(*fuseops.InternalInterruptOp); ok {
			c.handleInterrupt(interruptOp.FuseID)
			continue
		}

		return
	}
}

func (c *Connection) waitForReady() (err error) {
	<-c.wrapped.Ready
	err = c.wrapped.MountError
	return
}

// Close the connection. Must not be called until operations that were read
// from the connection have been responded to.
func (c *Connection) close() (err error) {
	err = c.wrapped.Close()
	return
}
<|endoftext|>


<commit_before>package rapid

import (
	"encoding/json"
	"fmt"
	"html/template"
	"net/http"

	"github.com/Kiricon/Rapid/templating"
)

// Connection - struct for handling http request and write
type Connection struct {
	R      *http.Request
	W      http.ResponseWriter
	Params map[string]string
	JSON   interface{}
	server *Server
}

// Send - Return plain text string back to http request
func (c *Connection) Send(message string) {
	fmt.Fprintf(c.W, message)
}

// View - Render HTML view without templating
func (c *Connection) View(path string) {
	c.Render(path, nil)
}

// Render - Render HTML view with templating
// Templating uses standard library templating
func (c *Connection) Render(path string, object interface{}) {

	fileString := templating.AddPartial(c.server.viewPrefix + path)
	t, _ := template.New("blah").Parse(fileString)
	c.W.Header().Set("Content-Type", "text/html; charset=utf-8")
	t.Execute(c.W, object)
}

// Redirect - Redirect a request to another rest end point
func (c *Connection) Redirect(path string) {
	http.Redirect(c.W, c.R, path, 301)
}

// NotFound - Return 404 message to user
func (c *Connection) NotFound() {
	if c.server.notFoundPage != "" {
		http.ServeFile(c.W, c.R, c.server.notFoundPage)
	} else {
		c.W.WriteHeader(http.StatusNotFound)
		fmt.Fprintf(c.W, c.server.notFoundMessage)
	}
}

// SendJSON - Send json string back to client
func (c *Connection) SendJSON(object interface{}) {
	obj := &object
	j, err := json.Marshal(obj)
	if err != nil {
		fmt.Println(err)
		return
	}
	c.W.Header().Set("Content-Type", "application/json")
	c.Send(string(j))
}
<commit_msg>Fixed the view prefix<commit_after>package rapid

import (
	"encoding/json"
	"fmt"
	"html/template"
	"net/http"

	"github.com/Kiricon/Rapid/templating"
)

// Connection - struct for handling http request and write
type Connection struct {
	R      *http.Request
	W      http.ResponseWriter
	Params map[string]string
	JSON   interface{}
	server *Server
}

// Send - Return plain text string back to http request
func (c *Connection) Send(message string) {
	fmt.Fprintf(c.W, message)
}

// View - Render HTML view without templating
func (c *Connection) View(path string) {
	c.Render(path, nil)
}

// Render - Render HTML view with templating
// Templating uses standard library templating
func (c *Connection) Render(path string, object interface{}) {

	if c.server.viewPrefix != "" {
		path = c.server.viewPrefix + "/" + path
	}
	fileString := templating.AddPartial(path)
	t, _ := template.New("blah").Parse(fileString)
	c.W.Header().Set("Content-Type", "text/html; charset=utf-8")
	t.Execute(c.W, object)
}

// Redirect - Redirect a request to another rest end point
func (c *Connection) Redirect(path string) {
	http.Redirect(c.W, c.R, path, 301)
}

// NotFound - Return 404 message to user
func (c *Connection) NotFound() {
	if c.server.notFoundPage != "" {
		http.ServeFile(c.W, c.R, c.server.notFoundPage)
	} else {
		c.W.WriteHeader(http.StatusNotFound)
		fmt.Fprintf(c.W, c.server.notFoundMessage)
	}
}

// SendJSON - Send json string back to client
func (c *Connection) SendJSON(object interface{}) {
	obj := &object
	j, err := json.Marshal(obj)
	if err != nil {
		fmt.Println(err)
		return
	}
	c.W.Header().Set("Content-Type", "application/json")
	c.Send(string(j))
}
<|endoftext|>


<commit_before>package main

// Just enough UPnP to be able to forward ports
//

import (
	"bytes"
	"jackpal/http"
	"os"
	"net"
	"strings"
	"strconv"
	"xml"
)

type upnpNAT struct {
	serviceURL string
	ourIP      string
}

type NAT interface {
	AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (err os.Error)
	DeletePortMapping(protocol string, externalPort int) (err os.Error)
}

func Discover() (nat NAT, err os.Error) {
	ssdp, err := net.ResolveUDPAddr("239.255.255.250:1900")
	if err != nil {
		return
	}
	conn, err := net.ListenPacket("udp4", ":0")
	if err != nil {
		return
	}
	socket := conn.(*net.UDPConn)
	defer socket.Close()

	err = socket.SetReadTimeout(3 * 1000 * 1000 * 1000)
	if err != nil {
		return
	}

	st := "ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n"
	buf := bytes.NewBufferString(
		"M-SEARCH * HTTP/1.1\r\n" +
			"HOST: 239.255.255.250:1900\r\n" +
			st +
			"MAN: \"ssdp:discover\"\r\n" +
			"MX: 2\r\n\r\n")
	message := buf.Bytes()
	answerBytes := make([]byte, 1024)
	for i := 0; i < 3; i++ {
		_, err = socket.WriteToUDP(message, ssdp)
		if err != nil {
			return
		}
		var n int
		n, _, err = socket.ReadFromUDP(answerBytes)
		if err != nil {
			continue
			// socket.Close()
			// return
		}
		answer := string(answerBytes[0:n])
		if strings.Index(answer, "\r\n"+st) < 0 {
			continue
		}
		locString := "\r\nLocation: "
		locIndex := strings.Index(answer, locString)
		if locIndex < 0 {
			continue
		}
		loc := answer[locIndex+len(locString):]
		endIndex := strings.Index(loc, "\r\n")
		if endIndex < 0 {
			continue
		}
		locURL := loc[0:endIndex]
		var serviceURL string
		serviceURL, err = getServiceURL(locURL)
		if err != nil {
			return
		}
		var ourIP string
		ourIP, err = getOurIP()
		if err != nil {
			return
		}
		nat = &upnpNAT{serviceURL: serviceURL, ourIP: ourIP}
		return
	}
	err = os.NewError("UPnP port discovery failed.")
	return
}

type Service struct {
	ServiceType string
	ControlURL  string
}

type DeviceList struct {
	Device []Device
}

type ServiceList struct {
	Service []Service
}

type Device struct {
	DeviceType  string
	DeviceList  DeviceList
	ServiceList ServiceList
}

type Root struct {
	Device Device
}

func getChildDevice(d *Device, deviceType string) *Device {
	dl := d.DeviceList.Device
	for i := 0; i < len(dl); i++ {
		if dl[i].DeviceType == deviceType {
			return &dl[i]
		}
	}
	return nil
}

func getChildService(d *Device, serviceType string) *Service {
	sl := d.ServiceList.Service
	for i := 0; i < len(sl); i++ {
		if sl[i].ServiceType == serviceType {
			return &sl[i]
		}
	}
	return nil
}

func getOurIP() (ip string, err os.Error) {
	hostname, err := os.Hostname()
	if err != nil {
		return
	}
	_, addrs, err := net.LookupHost(hostname)
	if err != nil {
		return
	}
	if len(addrs) < 1 {
		err = os.NewError("No addresses.")
		return
	}
	ip = addrs[0]
	return
}

func getServiceURL(rootURL string) (url string, err os.Error) {
	r, _, err := http.Get(rootURL)
	if err != nil {
		return
	}
	defer r.Body.Close()
	if r.StatusCode >= 400 {
		err = os.NewError(string(r.StatusCode))
		return
	}
	var root Root
	err = xml.Unmarshal(r.Body, &root)
	if err != nil {
		return
	}
	a := &root.Device
	if a.DeviceType != "urn:schemas-upnp-org:device:InternetGatewayDevice:1" {
		err = os.NewError("No InternetGatewayDevice")
		return
	}
	b := getChildDevice(a, "urn:schemas-upnp-org:device:WANDevice:1")
	if b == nil {
		err = os.NewError("No WANDevice")
		return
	}
	c := getChildDevice(b, "urn:schemas-upnp-org:device:WANConnectionDevice:1")
	if c == nil {
		err = os.NewError("No WANConnectionDevice")
		return
	}
	d := getChildService(c, "urn:schemas-upnp-org:service:WANIPConnection:1")
	if d == nil {
		err = os.NewError("No WANIPConnection")
		return
	}
	url = combineURL(rootURL, d.ControlURL)
	return
}

func combineURL(rootURL, subURL string) string {
	protocolEnd := "://"
	protoEndIndex := strings.Index(rootURL, protocolEnd)
	a := rootURL[protoEndIndex+len(protocolEnd):]
	rootIndex := strings.Index(a, "/")
	return rootURL[0:protoEndIndex+len(protocolEnd)+rootIndex] + subURL
}

type stringBuffer struct {
	base    string
	current string
}

func NewStringBuffer(s string) *stringBuffer { return &stringBuffer{s, s} }

func (sb *stringBuffer) Read(p []byte) (n int, err os.Error) {
	s := sb.current
	lenStr := len(s)
	if lenStr == 0 {
		return 0, os.EOF
	}
	n = len(p)
	if n > lenStr {
		n = lenStr
		err = os.EOF
	}
	for i := 0; i < n; i++ {
		p[i] = s[i]
	}
	sb.current = s[n:]
	return
}

func (sb *stringBuffer) Seek(offset int64, whence int) (ret int64, err os.Error) {
	var newOffset int64
	switch whence {
	case 0: // from beginning
		newOffset = offset
	case 1: // relative
		newOffset = int64(len(sb.base)-len(sb.current)) + offset
	case 2: // from end
		newOffset = int64(len(sb.base)) - offset
	default:
		err = os.NewError("bad whence")
		return
	}
	if newOffset < 0 || newOffset > int64(len(sb.base)) {
		err = os.NewError("offset out of range")
	} else {
		sb.current = sb.base[newOffset:]
		ret = newOffset
	}
	return
}

func soapRequest(url, function, message string) (r *http.Response, err os.Error) {
	fullMessage := "<?xml version=\"1.0\" ?>" +
		"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" +
		"<s:Body>" + message + "</s:Body></s:Envelope>"

	var req http.Request
	req.Method = "POST"
	req.Body = NewStringBuffer(fullMessage)
	req.UserAgent = "Darwin/10.0.0, UPnP/1.0, MiniUPnPc/1.3"
	req.Header = map[string]string{
		"Content-Type": "text/xml ; charset=\"utf-8\"",
		// "Transfer-Encoding": "chunked",
		"SOAPAction":    "\"urn:schemas-upnp-org:service:WANIPConnection:1#" + function + "\"",
		"Connection":    "Close",
		"Cache-Control": "no-cache",
		"Pragma":        "no-cache",
	}

	req.URL, err = http.ParseURL(url)
	if err != nil {
		return
	}

	// log.Stderr("soapRequest ", req)

	r, err = http.Send(&req)

	if r.StatusCode >= 400 {
		// log.Stderr(function, r.StatusCode)
		err = os.NewError("Error " + strconv.Itoa(r.StatusCode) + " for " + function)
		r.Body.Close()
		r = nil
		return
	}
	return
}

func (n *upnpNAT) GetStatusInfo() (err os.Error) {

	message := "<u:GetStatusInfo xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">\r\n" +
		"</u:GetStatusInfo>"

	var response *http.Response
	response, err = soapRequest(n.serviceURL, "GetStatusInfo", message)
	if err != nil {
		return
	}

	// TODO: Write a soap reply parser. It has to eat the Body and envelope tags...

	response.Body.Close()
	return
}

func (n *upnpNAT) AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (err os.Error) {

	message := "<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">\r\n" +
		"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort) +
		"</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>" +
		"<NewInternalPort>" + strconv.Itoa(internalPort) + "</NewInternalPort>" +
		"<NewInternalClient>" + n.ourIP + "</NewInternalClient>" +
		"<NewEnabled>1</NewEnabled><NewPortMappingDescription>" +
		description +
		"</NewPortMappingDescription><NewLeaseDuration>" + strconv.Itoa(timeout) + "</NewLeaseDuration></u:AddPortMapping>"

	var response *http.Response
	response, err = soapRequest(n.serviceURL, "AddPortMapping", message)
	if err != nil {
		return
	}

	// TODO: check response to see if the port was forwarded
	// log.Stderr(message, response)
	_ = response
	return
}

func (n *upnpNAT) DeletePortMapping(protocol string, externalPort int) (err os.Error) {

	message := "<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">\r\n" +
		"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort) +
		"</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>" +
		"</u:DeletePortMapping>"

	var response *http.Response
	response, err = soapRequest(n.serviceURL, "DeletePortMapping", message)
	if err != nil {
		return
	}

	// TODO: check response to see if the port was deleted
	// log.Stderr(message, response)
	_ = response
	return
}
<commit_msg>Fix case-sensitivity bug for HTTP header field names in the UPnP client code.<commit_after>package main

// Just enough UPnP to be able to forward ports
//

import (
	"bytes"
	"jackpal/http"
	"os"
	"net"
	"strings"
	"strconv"
	"xml"
)

type upnpNAT struct {
	serviceURL string
	ourIP      string
}

type NAT interface {
	AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (err os.Error)
	DeletePortMapping(protocol string, externalPort int) (err os.Error)
}

func Discover() (nat NAT, err os.Error) {
	ssdp, err := net.ResolveUDPAddr("239.255.255.250:1900")
	if err != nil {
		return
	}
	conn, err := net.ListenPacket("udp4", ":0")
	if err != nil {
		return
	}
	socket := conn.(*net.UDPConn)
	defer socket.Close()

	err = socket.SetReadTimeout(3 * 1000 * 1000 * 1000)
	if err != nil {
		return
	}

	st := "ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n"
	buf := bytes.NewBufferString(
		"M-SEARCH * HTTP/1.1\r\n" +
			"HOST: 239.255.255.250:1900\r\n" +
			st +
			"MAN: \"ssdp:discover\"\r\n" +
			"MX: 2\r\n\r\n")
	message := buf.Bytes()
	answerBytes := make([]byte, 1024)
	for i := 0; i < 3; i++ {
		_, err = socket.WriteToUDP(message, ssdp)
		if err != nil {
			return
		}
		var n int
		n, _, err = socket.ReadFromUDP(answerBytes)
		if err != nil {
			continue
			// socket.Close()
			// return
		}
		answer := string(answerBytes[0:n])
		if strings.Index(answer, "\r\n"+st) < 0 {
			continue
		}
		// HTTP header field names are case-insensitive.
		// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
		locString := "\r\nlocation: "
		answer = strings.ToLower(answer)
		locIndex := strings.Index(answer, locString)
		if locIndex < 0 {
			continue
		}
		loc := answer[locIndex+len(locString):]
		endIndex := strings.Index(loc, "\r\n")
		if endIndex < 0 {
			continue
		}
		locURL := loc[0:endIndex]
		var serviceURL string
		serviceURL, err = getServiceURL(locURL)
		if err != nil {
			return
		}
		var ourIP string
		ourIP, err = getOurIP()
		if err != nil {
			return
		}
		nat = &upnpNAT{serviceURL: serviceURL, ourIP: ourIP}
		return
	}
	err = os.NewError("UPnP port discovery failed.")
	return
}

type Service struct {
	ServiceType string
	ControlURL  string
}

type DeviceList struct {
	Device []Device
}

type ServiceList struct {
	Service []Service
}

type Device struct {
	DeviceType  string
	DeviceList  DeviceList
	ServiceList ServiceList
}

type Root struct {
	Device Device
}

func getChildDevice(d *Device, deviceType string) *Device {
	dl := d.DeviceList.Device
	for i := 0; i < len(dl); i++ {
		if dl[i].DeviceType == deviceType {
			return &dl[i]
		}
	}
	return nil
}

func getChildService(d *Device, serviceType string) *Service {
	sl := d.ServiceList.Service
	for i := 0; i < len(sl); i++ {
		if sl[i].ServiceType == serviceType {
			return &sl[i]
		}
	}
	return nil
}

func getOurIP() (ip string, err os.Error) {
	hostname, err := os.Hostname()
	if err != nil {
		return
	}
	_, addrs, err := net.LookupHost(hostname)
	if err != nil {
		return
	}
	if len(addrs) < 1 {
		err = os.NewError("No addresses.")
		return
	}
	ip = addrs[0]
	return
}

func getServiceURL(rootURL string) (url string, err os.Error) {
	r, _, err := http.Get(rootURL)
	if err != nil {
		return
	}
	defer r.Body.Close()
	if r.StatusCode >= 400 {
		err = os.NewError(string(r.StatusCode))
		return
	}
	var root Root
	err = xml.Unmarshal(r.Body, &root)
	if err != nil {
		return
	}
	a := &root.Device
	if a.DeviceType != "urn:schemas-upnp-org:device:InternetGatewayDevice:1" {
		err = os.NewError("No InternetGatewayDevice")
		return
	}
	b := getChildDevice(a, "urn:schemas-upnp-org:device:WANDevice:1")
	if b == nil {
		err = os.NewError("No WANDevice")
		return
	}
	c := getChildDevice(b, "urn:schemas-upnp-org:device:WANConnectionDevice:1")
	if c == nil {
		err = os.NewError("No WANConnectionDevice")
		return
	}
	d := getChildService(c, "urn:schemas-upnp-org:service:WANIPConnection:1")
	if d == nil {
		err = os.NewError("No WANIPConnection")
		return
	}
	url = combineURL(rootURL, d.ControlURL)
	return
}

func combineURL(rootURL, subURL string) string {
	protocolEnd := "://"
	protoEndIndex := strings.Index(rootURL, protocolEnd)
	a := rootURL[protoEndIndex+len(protocolEnd):]
	rootIndex := strings.Index(a, "/")
	return rootURL[0:protoEndIndex+len(protocolEnd)+rootIndex] + subURL
}

type stringBuffer struct {
	base    string
	current string
}

func NewStringBuffer(s string) *stringBuffer { return &stringBuffer{s, s} }

func (sb *stringBuffer) Read(p []byte) (n int, err os.Error) {
	s := sb.current
	lenStr := len(s)
	if lenStr == 0 {
		return 0, os.EOF
	}
	n = len(p)
	if n > lenStr {
		n = lenStr
		err = os.EOF
	}
	for i := 0; i < n; i++ {
		p[i] = s[i]
	}
	sb.current = s[n:]
	return
}

func (sb *stringBuffer) Seek(offset int64, whence int) (ret int64, err os.Error) {
	var newOffset int64
	switch whence {
	case 0: // from beginning
		newOffset = offset
	case 1: // relative
		newOffset = int64(len(sb.base)-len(sb.current)) + offset
	case 2: // from end
		newOffset = int64(len(sb.base)) - offset
	default:
		err = os.NewError("bad whence")
		return
	}
	if newOffset < 0 || newOffset > int64(len(sb.base)) {
		err = os.NewError("offset out of range")
	} else {
		sb.current = sb.base[newOffset:]
		ret = newOffset
	}
	return
}

func soapRequest(url, function, message string) (r *http.Response, err os.Error) {
	fullMessage := "<?xml version=\"1.0\" ?>" +
		"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" +
		"<s:Body>" + message + "</s:Body></s:Envelope>"

	var req http.Request
	req.Method = "POST"
	req.Body = NewStringBuffer(fullMessage)
	req.UserAgent = "Darwin/10.0.0, UPnP/1.0, MiniUPnPc/1.3"
	req.Header = map[string]string{
		"Content-Type": "text/xml ; charset=\"utf-8\"",
		// "Transfer-Encoding": "chunked",
		"SOAPAction":    "\"urn:schemas-upnp-org:service:WANIPConnection:1#" + function + "\"",
		"Connection":    "Close",
		"Cache-Control": "no-cache",
		"Pragma":        "no-cache",
	}

	req.URL, err = http.ParseURL(url)
	if err != nil {
		return
	}

	// log.Stderr("soapRequest ", req)

	r, err = http.Send(&req)

	if r.StatusCode >= 400 {
		// log.Stderr(function, r.StatusCode)
		err = os.NewError("Error " + strconv.Itoa(r.StatusCode) + " for " + function)
		r.Body.Close()
		r = nil
		return
	}
	return
}

func (n *upnpNAT) GetStatusInfo() (err os.Error) {

	message := "<u:GetStatusInfo xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">\r\n" +
		"</u:GetStatusInfo>"

	var response *http.Response
	response, err = soapRequest(n.serviceURL, "GetStatusInfo", message)
	if err != nil {
		return
	}

	// TODO: Write a soap reply parser. It has to eat the Body and envelope tags...

	response.Body.Close()
	return
}

func (n *upnpNAT) AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (err os.Error) {

	message := "<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">\r\n" +
		"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort) +
		"</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>" +
		"<NewInternalPort>" + strconv.Itoa(internalPort) + "</NewInternalPort>" +
		"<NewInternalClient>" + n.ourIP + "</NewInternalClient>" +
		"<NewEnabled>1</NewEnabled><NewPortMappingDescription>" +
		description +
		"</NewPortMappingDescription><NewLeaseDuration>" + strconv.Itoa(timeout) + "</NewLeaseDuration></u:AddPortMapping>"

	var response *http.Response
	response, err = soapRequest(n.serviceURL, "AddPortMapping", message)
	if err != nil {
		return
	}

	// TODO: check response to see if the port was forwarded
	// log.Stderr(message, response)
	_ = response
	return
}

func (n *upnpNAT) DeletePortMapping(protocol string, externalPort int) (err os.Error) {

	message := "<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">\r\n" +
		"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort) +
		"</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>" +
		"</u:DeletePortMapping>"

	var response *http.Response
	response, err = soapRequest(n.serviceURL, "DeletePortMapping", message)
	if err != nil {
		return
	}

	// TODO: check response to see if the port was deleted
	// log.Stderr(message, response)
	_ = response
	return
}
<|endoftext|>


<commit_before>package gottp

import (
	"log"
	"net/http"
	"regexp"
)

type Url struct {
	name    string
	url     string
	handler Handler
	pattern *regexp.Regexp
}

var boundUrls = []*Url{}

func NewUrl(name string, pattern string, handler Handler) {
	compiled_pattern, err := regexp.Compile(pattern)
	if err != nil {
		panic(err)
	}

	url := Url{
		name:    name,
		handler: handler,
		pattern: compiled_pattern,
		url:     pattern,
	}

	boundUrls = append(boundUrls, &url)
}

func (u Url) MakeUrlArgs(url *string) (*map[string]string, bool) {
	matches := u.pattern.FindStringSubmatch(*url)
	named_groups := u.pattern.SubexpNames()
	data := map[string]string{}

	var err bool

	if len(matches) > 0 {
		for ix, key := range named_groups {
			if len(key) > 0 {
				data[key] = matches[ix]
			}
		}
	} else if len(named_groups) > 0 {
		err = true
	}

	return &data, err
}

func bindGlobalHandler() {
	http.HandleFunc("/", GlobalHandler)
}

func bindHandlers() {
	NewUrl("async_pipe", "^/async_pipe/?$", new(AsyncPipeHandler))
	NewUrl("async_pipe", "^/async_pipe/?$", new(PipeHandler))
	NewUrl("urls", "^/urls/?$", new(UrlHandler))
}

func init() {
	log.SetFlags(log.Lshortfile | log.Ldate | log.Ltime)
	bindGlobalHandler()
	bindHandlers()
}
<commit_msg>Add pipe instead of async_pipe for PipeHandler<commit_after>package gottp

import (
	"log"
	"net/http"
	"regexp"
)

type Url struct {
	name    string
	url     string
	handler Handler
	pattern *regexp.Regexp
}

var boundUrls = []*Url{}

func NewUrl(name string, pattern string, handler Handler) {
	compiled_pattern, err := regexp.Compile(pattern)
	if err != nil {
		panic(err)
	}

	url := Url{
		name:    name,
		handler: handler,
		pattern: compiled_pattern,
		url:     pattern,
	}

	boundUrls = append(boundUrls, &url)
}

func (u Url) MakeUrlArgs(url *string) (*map[string]string, bool) {
	matches := u.pattern.FindStringSubmatch(*url)
	named_groups := u.pattern.SubexpNames()
	data := map[string]string{}

	var err bool

	if len(matches) > 0 {
		for ix, key := range named_groups {
			if len(key) > 0 {
				data[key] = matches[ix]
			}
		}
	} else if len(named_groups) > 0 {
		err = true
	}

	return &data, err
}

func bindGlobalHandler() {
	http.HandleFunc("/", GlobalHandler)
}

func bindHandlers() {
	NewUrl("async_pipe", "^/async_pipe/?$", new(AsyncPipeHandler))
	NewUrl("pipe", "^/pipe/?$", new(PipeHandler))
	NewUrl("urls", "^/urls/?$", new(UrlHandler))
}

func init() {
	log.SetFlags(log.Lshortfile | log.Ldate | log.Ltime)
	bindGlobalHandler()
	bindHandlers()
}
<|endoftext|>


<commit_before>// vim: tabstop=2 shiftwidth=2

package main

import (
	"fmt"
	"github.com/crooks/yamn/idlog"
	"github.com/crooks/yamn/keymgr"
	"github.com/luksen/maildir"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

const (
	version        string = "0.2a"
	dayLength      int    = 24 * 60 * 60 // Day in seconds
	maxFragLength         = 10230
	maxCopies             = 5
	base64LineWrap        = 72
	rfc5322date           = "Mon, 2 Jan 2006 15:04:05 -0700"
	shortdate             = "2 Jan 2006"
)

var (
	Trace   *log.Logger
	Info    *log.Logger
	Warn    *log.Logger
	Error   *log.Logger
	Pubring *keymgr.Pubring
	IdDb    *idlog.IDLog
	ChunkDb *Chunk
)

func logInit(
	traceHandle io.Writer,
	infoHandle io.Writer,
	warnHandle io.Writer,
	errorHandle io.Writer) {

	Trace = log.New(traceHandle,
		"Trace: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Info = log.New(infoHandle,
		"Info: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Warn = log.New(warnHandle,
		"Warn: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Error = log.New(errorHandle,
		"Error: ",
		log.Ldate|log.Ltime|log.Lshortfile)
}

func main() {
	var err error
	flags()
	switch strings.ToLower(cfg.Remailer.Loglevel) {
	case "trace":
		logInit(os.Stdout, os.Stdout, os.Stdout, os.Stderr)
	case "info":
		logInit(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
	case "warn":
		logInit(ioutil.Discard, ioutil.Discard, os.Stdout, os.Stderr)
	case "error":
		logInit(ioutil.Discard, ioutil.Discard, ioutil.Discard, os.Stderr)
	default:
		fmt.Fprintf(os.Stderr, "Unknown loglevel: %s\n", cfg.Remailer.Loglevel)
	}
	if flag_client {
		mixprep()
		poolOutboundSend()
	} else if flag_stdin {
		dir := maildir.Dir(cfg.Files.Maildir)
		newmsg, err := dir.NewDelivery()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		stdin, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		newmsg.Write(stdin)
		newmsg.Close()
	} else if flag_remailer {
		err = loopServer()
		if err != nil {
			panic(err)
		}
	} else if flag_dummy {
		injectDummy()
	} else if flag_send {
		poolOutboundSend()
	}
}
<commit_msg>Increase fragment size to match payload size<commit_after>// vim: tabstop=2 shiftwidth=2

package main

import (
	"fmt"
	"github.com/crooks/yamn/idlog"
	"github.com/crooks/yamn/keymgr"
	"github.com/luksen/maildir"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

const (
	version        string = "0.2a"
	dayLength      int    = 24 * 60 * 60 // Day in seconds
	maxFragLength         = 17910
	maxCopies             = 5
	base64LineWrap        = 72
	rfc5322date           = "Mon, 2 Jan 2006 15:04:05 -0700"
	shortdate             = "2 Jan 2006"
)

var (
	Trace   *log.Logger
	Info    *log.Logger
	Warn    *log.Logger
	Error   *log.Logger
	Pubring *keymgr.Pubring
	IdDb    *idlog.IDLog
	ChunkDb *Chunk
)

func logInit(
	traceHandle io.Writer,
	infoHandle io.Writer,
	warnHandle io.Writer,
	errorHandle io.Writer) {

	Trace = log.New(traceHandle,
		"Trace: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Info = log.New(infoHandle,
		"Info: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Warn = log.New(warnHandle,
		"Warn: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Error = log.New(errorHandle,
		"Error: ",
		log.Ldate|log.Ltime|log.Lshortfile)
}

func main() {
	var err error
	flags()
	switch strings.ToLower(cfg.Remailer.Loglevel) {
	case "trace":
		logInit(os.Stdout, os.Stdout, os.Stdout, os.Stderr)
	case "info":
		logInit(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
	case "warn":
		logInit(ioutil.Discard, ioutil.Discard, os.Stdout, os.Stderr)
	case "error":
		logInit(ioutil.Discard, ioutil.Discard, ioutil.Discard, os.Stderr)
	default:
		fmt.Fprintf(os.Stderr, "Unknown loglevel: %s\n", cfg.Remailer.Loglevel)
	}
	if flag_client {
		mixprep()
		poolOutboundSend()
	} else if flag_stdin {
		dir := maildir.Dir(cfg.Files.Maildir)
		newmsg, err := dir.NewDelivery()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		stdin, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		newmsg.Write(stdin)
		newmsg.Close()
	} else if flag_remailer {
		err = loopServer()
		if err != nil {
			panic(err)
		}
	} else if flag_dummy {
		injectDummy()
	} else if flag_send {
		poolOutboundSend()
	}
}
<|endoftext|>


<commit_before>package model

import (
	"github.com/geotrace/uid"
	"gopkg.in/mgo.v2/bson"
)

// User описывает информацию о пользователе.
//
// Логин пользователя является глобальным уникальным идентификатором
// пользователя и не может повторяться для разных пользователей. Поэтому, скорее
// всего, удобнее использовать в качестве такого идентификатора e-mail, что
// избавит от головной боли с уникальностью. Или любой другой идентификатор,
// который будет действительно глобально уникальным.
//
// Пользователи объединяются в группы, которые разделяют общие ресурсы: имеют
// доступ к трекам устройств той же группы, общие описания мест и так далее.
// Пользователь может состоять только в одной группе, но может ее сменить.
// Идентификатор группы генерируется непосредственно сервером.
//
// Пароль пользователя не хранится в системе, а вместо этого хранится хеш от
// него: этого вполне достаточно, чтобы иметь возможность проверить правильность
// введенного пароля, но не позволит его восстановить в исходном виде. В
// качестве алгоритма хеширования выбран bcrypt (Provos and Mazières's bcrypt
// adaptive hashing algorithm).
type User struct {
	// логин пользователя
	Login string `bson:"_id" json:"login"`
	// уникальный идентификатор группы
	GroupID string `bson:"groupId,omitempty" json:"groupId,omitempty"`
	// отображаемое имя
	Name string `bson:"name,omitempty" json:"name,omitempty"`
	// хеш пароля пользователя
	Password Password `bson:"password" json:"-"`
}

// Login возвращает информацию о пользователе по его логину.
func (db *Users) Login(userID string) (user *User, err error) {
	session := db.session.Copy()
	coll := session.DB(db.name).C(CollectionUsers)
	err = coll.FindId(userID).One(&user)
	session.Close()
	return
}

// List возвращает список всех пользователей, зарегистрированных в указанной
// группе.
func (db *Users) List(groupID string) (users []User, err error) {
	session := db.session.Copy()
	coll := session.DB(db.name).C(CollectionUsers)
	users = make([]User, 0)
	err = coll.Find(bson.M{"groupId": groupID}).
		Select(bson.M{"password": 0, "groupId": 0}).All(&users)
	session.Close()
	return
}

// Create создает нового пользователя по его описанию. Поле Login должно быть
// уникальным, в противном случае возвращается ошибка.
func (db *Users) Create(user *User) (err error) {
	if user.Login == "" {
		user.Login = uid.New()
	}
	session := db.session.Copy()
	coll := session.DB(db.name).C(CollectionUsers)
	err = coll.Insert(user)
	session.Close()
	return
}

// Update обновляет информацию о пользователе в хранилище.
func (db *Users) Update(user User) (err error) {
	session := db.session.Copy()
	coll := session.DB(db.name).C(CollectionUsers)
	err = coll.UpdateId(user.Login, user)
	session.Close()
	return
}

// Delete удаляет пользователя с указанным логином из хранилища.
func (db *Users) Delete(login string) (err error) {
	session := db.session.Copy()
	coll := session.DB(db.name).C(CollectionUsers)
	err = coll.RemoveId(login)
	session.Close()
	return
}
<commit_msg>login -> id<commit_after>package model

import (
	"github.com/geotrace/uid"
	"gopkg.in/mgo.v2/bson"
)

// User описывает информацию о пользователе.
//
// Логин пользователя является глобальным уникальным идентификатором
// пользователя и не может повторяться для разных пользователей. Поэтому, скорее
// всего, удобнее использовать в качестве такого идентификатора e-mail, что
// избавит от головной боли с уникальностью. Или любой другой идентификатор,
// который будет действительно глобально уникальным.
//
// Пользователи объединяются в группы, которые разделяют общие ресурсы: имеют
// доступ к трекам устройств той же группы, общие описания мест и так далее.
// Пользователь может состоять только в одной группе, но может ее сменить.
// Идентификатор группы генерируется непосредственно сервером.
//
// Пароль пользователя не хранится в системе, а вместо этого хранится хеш от
// него: этого вполне достаточно, чтобы иметь возможность проверить правильность
// введенного пароля, но не позволит его восстановить в исходном виде. В
// качестве алгоритма хеширования выбран bcrypt (Provos and Mazières's bcrypt
// adaptive hashing algorithm).
type User struct {
	// логин пользователя
	Login string `bson:"_id" json:"id"`
	// уникальный идентификатор группы
	GroupID string `bson:"groupId,omitempty" json:"groupId,omitempty"`
	// отображаемое имя
	Name string `bson:"name,omitempty" json:"name,omitempty"`
	// хеш пароля пользователя
	Password Password `bson:"password" json:"-"`
}

// Login возвращает информацию о пользователе по его логину.
func (db *Users) Login(userID string) (user *User, err error) {
	session := db.session.Copy()
	coll := session.DB(db.name).C(CollectionUsers)
	err = coll.FindId(userID).One(&user)
	session.Close()
	return
}

// List возвращает список всех пользователей, зарегистрированных в указанной
// группе.
func (db *Users) List(groupID string) (users []User, err error) {
	session := db.session.Copy()
	coll := session.DB(db.name).C(CollectionUsers)
	users = make([]User, 0)
	err = coll.Find(bson.M{"groupId": groupID}).
		Select(bson.M{"password": 0, "groupId": 0}).All(&users)
	session.Close()
	return
}

// Create создает нового пользователя по его описанию. Поле Login должно быть
// уникальным, в противном случае возвращается ошибка.
func (db *Users) Create(user *User) (err error) {
	if user.Login == "" {
		user.Login = uid.New()
	}
	session := db.session.Copy()
	coll := session.DB(db.name).C(CollectionUsers)
	err = coll.Insert(user)
	session.Close()
	return
}

// Update обновляет информацию о пользователе в хранилище.
func (db *Users) Update(user User) (err error) {
	session := db.session.Copy()
	coll := session.DB(db.name).C(CollectionUsers)
	err = coll.UpdateId(user.Login, user)
	session.Close()
	return
}

// Delete удаляет пользователя с указанным логином из хранилища.
func (db *Users) Delete(login string) (err error) {
	session := db.session.Copy()
	coll := session.DB(db.name).C(CollectionUsers)
	err = coll.RemoveId(login)
	session.Close()
	return
}
<|endoftext|>


<commit_before>package subnet

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"log"
	"net"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

//SetInterfaceStatus brings up or down a network interface.
func SetInterfaceStatus(iName string, up bool, debug bool) error {
	statusString := "down"
	if up {
		statusString = "up"
	}
	sargs := fmt.Sprintf("link set dev %s %s mtu %d qlen %d", iName, statusString, devMtuSize, devTxQueLen)
	args := strings.Split(sargs, " ")
	return commandExec("ip", args, debug)
}

//SetDevIP sets the local IP address of a network interface.
func SetDevIP(iName string, localAddr net.IP, addr *net.IPNet, debug bool) error {
	sargs := fmt.Sprintf("%s %s netmask %s", iName, localAddr.String(), net.IP(addr.Mask).String())
	args := strings.Split(sargs, " ")
	return commandExec("ifconfig", args, debug)
}

// SetDefaultGateway sets the systems gateway to the IP / device specified.
func SetDefaultGateway(gw, iName string, debug bool) error {
	sargs := fmt.Sprintf("add default gw %s dev %s", gw, iName)
	args := strings.Split(sargs, " ")
	return commandExec("route", args, debug)
}

// AddRoute routes all traffic for addr via interface iName.
func AddRoute(addr, viaAddr net.IP, iName string, debug bool) error {
	sargs := fmt.Sprintf("add %s gw %s dev %s", addr.String(), viaAddr.String(), iName)
	args := strings.Split(sargs, " ")
	return commandExec("route", args, debug)
}

// DelRoute deletes the route in the system routing table to a specific destination.
func DelRoute(addr, viaAddr net.IP, iName string, debug bool) error {
	sargs := fmt.Sprintf("del %s gw %s dev %s", addr.String(), viaAddr.String(), iName)
	args := strings.Split(sargs, " ")
	return commandExec("route", args, debug)
}

func commandExec(command string, args []string, debug bool) error {
	cmd := exec.Command(command, args...)
	if debug {
		log.Println("exec "+command+": ", args)
	}
	e := cmd.Run()
	if e != nil {
		log.Println("Command failed: ", e)
	}
	return e
}

// GetNetGateway return net gateway (default route) and nic.
// Credit: https://github.com/bigeagle/gohop/blob/master/hop/iface.go
func GetNetGateway() (gw, dev string, err error) {
	file, err := os.Open("/proc/net/route")
	if err != nil {
		return "", "", err
	}

	defer file.Close()
	rd := bufio.NewReader(file)

	s2byte := func(s string) byte {
		b, _ := strconv.ParseUint(s, 16, 8)
		return byte(b)
	}

	for {
		line, isPrefix, err := rd.ReadLine()

		if err != nil {
			return "", "", err
		}
		if isPrefix {
			return "", "", errors.New("Parse error: Line too long")
		}
		buf := bytes.NewBuffer(line)
		scanner := bufio.NewScanner(buf)
		scanner.Split(bufio.ScanWords)
		tokens := make([]string, 0, 8)

		for scanner.Scan() {
			tokens = append(tokens, scanner.Text())
		}

		iface := tokens[0]
		dest := tokens[1]
		gw := tokens[2]
		mask := tokens[7]

		if bytes.Equal([]byte(dest), []byte("00000000")) &&
			bytes.Equal([]byte(mask), []byte("00000000")) {
			a := s2byte(gw[6:8])
			b := s2byte(gw[4:6])
			c := s2byte(gw[2:4])
			d := s2byte(gw[0:2])

			ip := net.IPv4(a, b, c, d)

			return ip.String(), iface, nil
		}

	}
}
<commit_msg>Fix broken build on linux<commit_after>package subnet

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"log"
	"net"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

//SetInterfaceStatus brings up or down a network interface.
func SetInterfaceStatus(iName string, up bool, debug bool) error {
	statusString := "down"
	if up {
		statusString = "up"
	}
	sargs := fmt.Sprintf("link set dev %s %s mtu %d qlen %d", iName, statusString, devMtuSize, devTxQueLen)
	args := strings.Split(sargs, " ")
	return commandExec("ip", args, debug)
}

//SetDevIP sets the local IP address of a network interface.
func SetDevIP(iName string, localAddr net.IP, addr *net.IPNet, debug bool) error {
	sargs := fmt.Sprintf("%s %s netmask %s", iName, localAddr.String(), net.IP(addr.Mask).String())
	args := strings.Split(sargs, " ")
	return commandExec("ifconfig", args, debug)
}

// SetDefaultGateway sets the systems gateway to the IP / device specified.
func SetDefaultGateway(gw, iName string, debug bool) error {
	sargs := fmt.Sprintf("add default gw %s dev %s", gw, iName)
	args := strings.Split(sargs, " ")
	return commandExec("route", args, debug)
}

// AddRoute routes all traffic for addr via interface iName.
func AddRoute(addr, viaAddr net.IP, iName string, debug bool) error {
	sargs := fmt.Sprintf("add %s gw %s dev %s", addr.String(), viaAddr.String(), iName)
	args := strings.Split(sargs, " ")
	return commandExec("route", args, debug)
}

// DelRoute deletes the route in the system routing table to a specific destination.
func DelRoute(addr, viaAddr net.IP, iName string, debug bool) error {
	sargs := fmt.Sprintf("del %s gw %s dev %s", addr.String(), viaAddr.String(), iName)
	args := strings.Split(sargs, " ")
	return commandExec("route", args, debug)
}

// GetNetGateway return net gateway (default route) and nic.
// Credit: https://github.com/bigeagle/gohop/blob/master/hop/iface.go
func GetNetGateway() (gw, dev string, err error) {
	file, err := os.Open("/proc/net/route")
	if err != nil {
		return "", "", err
	}

	defer file.Close()
	rd := bufio.NewReader(file)

	s2byte := func(s string) byte {
		b, _ := strconv.ParseUint(s, 16, 8)
		return byte(b)
	}

	for {
		line, isPrefix, err := rd.ReadLine()

		if err != nil {
			return "", "", err
		}
		if isPrefix {
			return "", "", errors.New("Parse error: Line too long")
		}
		buf := bytes.NewBuffer(line)
		scanner := bufio.NewScanner(buf)
		scanner.Split(bufio.ScanWords)
		tokens := make([]string, 0, 8)

		for scanner.Scan() {
			tokens = append(tokens, scanner.Text())
		}

		iface := tokens[0]
		dest := tokens[1]
		gw := tokens[2]
		mask := tokens[7]

		if bytes.Equal([]byte(dest), []byte("00000000")) &&
			bytes.Equal([]byte(mask), []byte("00000000")) {
			a := s2byte(gw[6:8])
			b := s2byte(gw[4:6])
			c := s2byte(gw[2:4])
			d := s2byte(gw[0:2])

			ip := net.IPv4(a, b, c, d)

			return ip.String(), iface, nil
		}

	}
}
<|endoftext|>


<commit_before>package zgok

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

const (
	APP   = "zgok" // Application name.
	MAJOR = 0      // Major version.
	MINOR = 0      // Minor version.
	REV   = 1      // Revision.
)

// Get version string.
func Version() string {
	return fmt.Sprintf("%s-%d.%d.%d", APP, MAJOR, MINOR, REV)
}

// File system interface.
// Implements [net/http.FileSystem]
type FileSystem interface {
	AddFile(file File)
	GetFile(path string) (File, error)
	ReadFile(path string) ([]byte, error)
	ReadFileString(path string) (string, error)
	Paths() []string
	SubFileSystem(rootPath string) (FileSystem, error)
	Signature() Signature
	SetSignature(signature Signature)
	String() string
	Open(name string) (http.File, error)     // Implements [net/http.FileSystem.Open]
	FileServer(basePath string) http.Handler // Get a static file server.
}

// Zgok file system.
type zgokFileSystem struct {
	signature Signature       // Zgok signature.
	rootPath  string          // Root path of the file system.
	fileMap   map[string]File // Map of files.
}

// Create a new file system.
func NewFileSystem() FileSystem {
	return &zgokFileSystem{
		signature: nil,
		rootPath:  APP,
		fileMap:   make(map[string]File),
	}
}

// Restore file system.
func RestoreFileSystem(path string) (FileSystem, error) {
	// Get bytes of exe file.
	exeBytes, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	// Restore signature.
	sigOffset := len(exeBytes) - SIGNATURE_BYTE_SIZE
	sigBytes := exeBytes[sigOffset:]
	signature, err := RestoreSignature(sigBytes)
	if err != nil {
		return nil, err
	}
	// Unzip zip section.
	zipOffset := signature.ExeSize()
	zipBytes := exeBytes[zipOffset:sigOffset]
	unzipper := NewUnzipper(&zipBytes)
	zfs, err := unzipper.Unzip()
	if err != nil {
		return nil, err
	}
	// Set signature.
	zfs.SetSignature(signature)
	return zfs, nil
}

// Add file to file system.
func (zfs *zgokFileSystem) AddFile(file File) {
	key := filepath.ToSlash(file.Path())
	zfs.fileMap[key] = file
}

// Get file from file system.
func (zfs *zgokFileSystem) GetFile(path string) (File, error) {
	key := filepath.ToSlash(filepath.Join(zfs.rootPath, path))
	file, exists := zfs.fileMap[key]
	if !exists {
		return nil, errors.New("File doesn't exist.")
	}
	return file, nil
}

// Get the content of file in bytes from file system.
func (zfs *zgokFileSystem) ReadFile(path string) ([]byte, error) {
	file, err := zfs.GetFile(path)
	if err != nil {
		return []byte{}, nil
	}
	return file.Bytes(), nil
}

// Get the content of file in string from file system.
func (zfs *zgokFileSystem) ReadFileString(path string) (string, error) {
	bytes, err := zfs.ReadFile(path)
	if err != nil {
		return "", nil
	}
	str := string(bytes)
	return str, nil
}

// Get all the paths stored in the file system.
func (zfs *zgokFileSystem) Paths() []string {
	paths := []string{}
	prefix := zfs.rootPath + "/"
	for key := range zfs.fileMap {
		if strings.HasPrefix(key, prefix) {
			relPath := strings.TrimPrefix(key, prefix)
			paths = append(paths, relPath)
		}
	}
	sort.Strings(paths)
	return paths
}

// Get a sub file system.
func (zfs *zgokFileSystem) SubFileSystem(rootPath string) (FileSystem, error) {
	// Check root path.
	if strings.Contains(rootPath, "..") {
		return nil, errors.New("No double dots [..] are allowed in root path.")
	}
	// Initialize sub file system.
	newRootPath := filepath.ToSlash(filepath.Join(zfs.rootPath, rootPath))
	subFs := &zgokFileSystem{
		signature: zfs.signature,
		rootPath:  newRootPath,
		fileMap:   make(map[string]File),
	}
	// Add all the sets matching the new root path.
	for key, value := range zfs.fileMap {
		if key[0:len(newRootPath)] == newRootPath {
			subFs.fileMap[key] = value
		}
	}
	return subFs, nil
}

// Get signature.
func (zfs *zgokFileSystem) Signature() Signature {
	return zfs.signature
}

// Set signature.
func (zfs *zgokFileSystem) SetSignature(signature Signature) {
	zfs.signature = signature
}

// Get string.
func (zfs *zgokFileSystem) String() string {
	return zfs.Signature().String()
}

// Open the file.
// Implements [net/http.FileSystem.Open]
func (zfs *zgokFileSystem) Open(name string) (http.File, error) {
	path := strings.TrimLeft(name, "/")
	file, err := zfs.GetFile(path)
	if err != nil {
		// Return an abstract directory.
		dir := &zgokFile{
			fileInfo: zgokFileInfo{
				name: filepath.Base(path),
				mode: os.ModeDir | os.ModePerm,
			},
		}
		return dir, nil
	}
	// Set a new file reader
	file.SetNewReader()
	return file, nil
}

// File interface.
type File interface {
	SetPath(path string)                          // Set file path.
	Path() string                                 // Get file path.
	SetFileInfo(fileInfo os.FileInfo)             // Set file info.
	FileInfo() os.FileInfo                        // Get file info.
	SetBytes(content []byte)                      // Set content bytes.
	Bytes() []byte                                // Get content bytes.
	SetNewReader()                                // Set a new reader.
	Close() error                                 // Implements [net/http.File.Close]
	Read(p []byte) (int, error)                   // Implements [net/http.File.Read]
	Readdir(count int) ([]os.FileInfo, error)     // Implements [net/http.File.Readdir]
	Seek(offset int64, whence int) (int64, error) // Implements [net/http.File.Seek]
	Stat() (os.FileInfo, error)                   // Implements [net/http.File.Stat]
}

// Zgok file.
type zgokFile struct {
	path     string        // Path of the file.
	fileInfo os.FileInfo   // File info.
	content  []byte        // Content of the file.
	reader   *bytes.Reader // File reader.
}

// Create a new zgok file.
func NewZgokFile() File {
	return &zgokFile{}
}

// Set file path.
func (zf *zgokFile) SetPath(path string) {
	zf.path = strings.Replace(path, `\`, "/", -1)
}

// Get file path.
func (zf *zgokFile) Path() string {
	return zf.path
}

// Set file info.
func (zf *zgokFile) SetFileInfo(fileInfo os.FileInfo) {
	zf.fileInfo = fileInfo
}

// Get file info.
func (zf *zgokFile) FileInfo() os.FileInfo {
	return zf.fileInfo
}

// Set content bytes.
func (zf *zgokFile) SetBytes(content []byte) {
	zf.content = content
}

// Get content bytes.
func (zf *zgokFile) Bytes() []byte {
	return zf.content
}

// Set a new reader.
func (zf *zgokFile) SetNewReader() {
	reader := bytes.NewReader(zf.content)
	zf.reader = reader
}

// Close file.
// Implements [net/http.File.Close]
func (zf *zgokFile) Close() error {
	return nil
}

// Read file.
// Implements [net/http.File.Read]
func (zf *zgokFile) Read(p []byte) (int, error) {
	return zf.reader.Read(p)
}

// Read directories.
// Implements [net/http.File.Readdir]
func (zf *zgokFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, errors.New("Readdir is not allowed.")
}

// Seek file.
// Implements [net/http.File.Seek]
func (zf *zgokFile) Seek(offset int64, whence int) (int64, error) {
	return zf.reader.Seek(offset, whence)
}

// Get file info.
// Implements [net/http.File.Stat]
func (zf *zgokFile) Stat() (os.FileInfo, error) {
	return zf.fileInfo, nil
}

// Zgok file info.
// Implements [os.FileInfo]
type zgokFileInfo struct {
	name    string      // File name.
	size    int64       // Size of the file.
	mode    os.FileMode // File mode.
	modTime time.Time   // Modified time of the file.
}

// Get name.
// Implements [os.FileInfo.Name]
func (i zgokFileInfo) Name() string {
	return i.name
}

// Get size.
// Implements [os.FileInfo.Size]
func (i zgokFileInfo) Size() int64 {
	return i.size
}

// Get mode.
// Implements [os.FileInfo.Mode]
func (i zgokFileInfo) Mode() os.FileMode {
	return i.mode
}

// Get modified time.
// Implements [os.FileInfo.ModTime]
func (i zgokFileInfo) ModTime() time.Time {
	return i.modTime
}

// Check if it is a directory.
// Implements [os.FileInfo.IsDir]
func (i zgokFileInfo) IsDir() bool {
	return i.mode.IsDir()
}

// Get sys information. (Only returns nil.)
// Implements [os.FileInfo.Sys]
func (i zgokFileInfo) Sys() interface{} {
	return nil
}
<commit_msg>Add Added zgok package description.<commit_after>/*
Package zgok provides a simple library to create a single binary with asset files in Go (Golang).

Example:

	package main

	import (
		"net/http"
		"github.com/srtkkou/zgok"
		"os"
	)

	func main() {
		zfs, err := zgok.RestoreFileSystem(os.Args[0])
		if err != nil {
			panic(err)
		}
		assetServer := zfs.FileServer("web/public")
		http.Handle("/assets/", http.StripPrefix("/assets/", assetServer))
		http.ListenAndServe(":8080", nil)
	}
*/
package zgok

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

const (
	APP   = "zgok" // Application name.
	MAJOR = 0      // Major version.
	MINOR = 0      // Minor version.
	REV   = 1      // Revision.
)

// Get version string.
func Version() string {
	return fmt.Sprintf("%s-%d.%d.%d", APP, MAJOR, MINOR, REV)
}

// File system interface.
// Implements [net/http.FileSystem]
type FileSystem interface {
	AddFile(file File)
	GetFile(path string) (File, error)
	ReadFile(path string) ([]byte, error)
	ReadFileString(path string) (string, error)
	Paths() []string
	SubFileSystem(rootPath string) (FileSystem, error)
	Signature() Signature
	SetSignature(signature Signature)
	String() string
	Open(name string) (http.File, error)     // Implements [net/http.FileSystem.Open]
	FileServer(basePath string) http.Handler // Get a static file server.
}

// Zgok file system.
type zgokFileSystem struct {
	signature Signature       // Zgok signature.
	rootPath  string          // Root path of the file system.
	fileMap   map[string]File // Map of files.
}

// Create a new file system.
func NewFileSystem() FileSystem {
	return &zgokFileSystem{
		signature: nil,
		rootPath:  APP,
		fileMap:   make(map[string]File),
	}
}

// Restore file system.
func RestoreFileSystem(path string) (FileSystem, error) {
	// Get bytes of exe file.
	exeBytes, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	// Restore signature.
	sigOffset := len(exeBytes) - SIGNATURE_BYTE_SIZE
	sigBytes := exeBytes[sigOffset:]
	signature, err := RestoreSignature(sigBytes)
	if err != nil {
		return nil, err
	}
	// Unzip zip section.
	zipOffset := signature.ExeSize()
	zipBytes := exeBytes[zipOffset:sigOffset]
	unzipper := NewUnzipper(&zipBytes)
	zfs, err := unzipper.Unzip()
	if err != nil {
		return nil, err
	}
	// Set signature.
	zfs.SetSignature(signature)
	return zfs, nil
}

// Add file to file system.
func (zfs *zgokFileSystem) AddFile(file File) {
	key := filepath.ToSlash(file.Path())
	zfs.fileMap[key] = file
}

// Get file from file system.
func (zfs *zgokFileSystem) GetFile(path string) (File, error) {
	key := filepath.ToSlash(filepath.Join(zfs.rootPath, path))
	file, exists := zfs.fileMap[key]
	if !exists {
		return nil, errors.New("File doesn't exist.")
	}
	return file, nil
}

// Get the content of file in bytes from file system.
func (zfs *zgokFileSystem) ReadFile(path string) ([]byte, error) {
	file, err := zfs.GetFile(path)
	if err != nil {
		return []byte{}, nil
	}
	return file.Bytes(), nil
}

// Get the content of file in string from file system.
func (zfs *zgokFileSystem) ReadFileString(path string) (string, error) {
	bytes, err := zfs.ReadFile(path)
	if err != nil {
		return "", nil
	}
	str := string(bytes)
	return str, nil
}

// Get all the paths stored in the file system.
func (zfs *zgokFileSystem) Paths() []string {
	paths := []string{}
	prefix := zfs.rootPath + "/"
	for key := range zfs.fileMap {
		if strings.HasPrefix(key, prefix) {
			relPath := strings.TrimPrefix(key, prefix)
			paths = append(paths, relPath)
		}
	}
	sort.Strings(paths)
	return paths
}

// Get a sub file system.
func (zfs *zgokFileSystem) SubFileSystem(rootPath string) (FileSystem, error) {
	// Check root path.
	if strings.Contains(rootPath, "..") {
		return nil, errors.New("No double dots [..] are allowed in root path.")
	}
	// Initialize sub file system.
	newRootPath := filepath.ToSlash(filepath.Join(zfs.rootPath, rootPath))
	subFs := &zgokFileSystem{
		signature: zfs.signature,
		rootPath:  newRootPath,
		fileMap:   make(map[string]File),
	}
	// Add all the sets matching the new root path.
	for key, value := range zfs.fileMap {
		if key[0:len(newRootPath)] == newRootPath {
			subFs.fileMap[key] = value
		}
	}
	return subFs, nil
}

// Get signature.
func (zfs *zgokFileSystem) Signature() Signature {
	return zfs.signature
}

// Set signature.
func (zfs *zgokFileSystem) SetSignature(signature Signature) {
	zfs.signature = signature
}

// Get string.
func (zfs *zgokFileSystem) String() string {
	return zfs.Signature().String()
}

// Open the file.
// Implements [net/http.FileSystem.Open]
func (zfs *zgokFileSystem) Open(name string) (http.File, error) {
	path := strings.TrimLeft(name, "/")
	file, err := zfs.GetFile(path)
	if err != nil {
		// Return an abstract directory.
		dir := &zgokFile{
			fileInfo: zgokFileInfo{
				name: filepath.Base(path),
				mode: os.ModeDir | os.ModePerm,
			},
		}
		return dir, nil
	}
	// Set a new file reader
	file.SetNewReader()
	return file, nil
}

// File interface.
type File interface {
	SetPath(path string)                          // Set file path.
	Path() string                                 // Get file path.
	SetFileInfo(fileInfo os.FileInfo)             // Set file info.
	FileInfo() os.FileInfo                        // Get file info.
	SetBytes(content []byte)                      // Set content bytes.
	Bytes() []byte                                // Get content bytes.
	SetNewReader()                                // Set a new reader.
	Close() error                                 // Implements [net/http.File.Close]
	Read(p []byte) (int, error)                   // Implements [net/http.File.Read]
	Readdir(count int) ([]os.FileInfo, error)     // Implements [net/http.File.Readdir]
	Seek(offset int64, whence int) (int64, error) // Implements [net/http.File.Seek]
	Stat() (os.FileInfo, error)                   // Implements [net/http.File.Stat]
}

// Zgok file.
type zgokFile struct {
	path     string        // Path of the file.
	fileInfo os.FileInfo   // File info.
	content  []byte        // Content of the file.
	reader   *bytes.Reader // File reader.
}

// Create a new zgok file.
func NewZgokFile() File {
	return &zgokFile{}
}

// Set file path.
func (zf *zgokFile) SetPath(path string) {
	zf.path = strings.Replace(path, `\`, "/", -1)
}

// Get file path.
func (zf *zgokFile) Path() string {
	return zf.path
}

// Set file info.
func (zf *zgokFile) SetFileInfo(fileInfo os.FileInfo) {
	zf.fileInfo = fileInfo
}

// Get file info.
func (zf *zgokFile) FileInfo() os.FileInfo {
	return zf.fileInfo
}

// Set content bytes.
func (zf *zgokFile) SetBytes(content []byte) {
	zf.content = content
}

// Get content bytes.
func (zf *zgokFile) Bytes() []byte {
	return zf.content
}

// Set a new reader.
func (zf *zgokFile) SetNewReader() {
	reader := bytes.NewReader(zf.content)
	zf.reader = reader
}

// Close file.
// Implements [net/http.File.Close]
func (zf *zgokFile) Close() error {
	return nil
}

// Read file.
// Implements [net/http.File.Read]
func (zf *zgokFile) Read(p []byte) (int, error) {
	return zf.reader.Read(p)
}

// Read directories.
// Implements [net/http.File.Readdir]
func (zf *zgokFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, errors.New("Readdir is not allowed.")
}

// Seek file.
// Implements [net/http.File.Seek]
func (zf *zgokFile) Seek(offset int64, whence int) (int64, error) {
	return zf.reader.Seek(offset, whence)
}

// Get file info.
// Implements [net/http.File.Stat]
func (zf *zgokFile) Stat() (os.FileInfo, error) {
	return zf.fileInfo, nil
}

// Zgok file info.
// Implements [os.FileInfo]
type zgokFileInfo struct {
	name    string      // File name.
	size    int64       // Size of the file.
	mode    os.FileMode // File mode.
	modTime time.Time   // Modified time of the file.
}

// Get name.
// Implements [os.FileInfo.Name]
func (i zgokFileInfo) Name() string {
	return i.name
}

// Get size.
// Implements [os.FileInfo.Size]
func (i zgokFileInfo) Size() int64 {
	return i.size
}

// Get mode.
// Implements [os.FileInfo.Mode]
func (i zgokFileInfo) Mode() os.FileMode {
	return i.mode
}

// Get modified time.
// Implements [os.FileInfo.ModTime]
func (i zgokFileInfo) ModTime() time.Time {
	return i.modTime
}

// Check if it is a directory.
// Implements [os.FileInfo.IsDir]
func (i zgokFileInfo) IsDir() bool {
	return i.mode.IsDir()
}

// Get sys information. (Only returns nil.)
// Implements [os.FileInfo.Sys]
func (i zgokFileInfo) Sys() interface{} {
	return nil
}
<|endoftext|>


<commit_before>package generate

var modelTpl = `package {{.PackageName}}

// Code auto-generated; DO NOT EDIT

import (
	"errors"
	{{ if .Generate "JoinSQL" -}}
	"fmt"
	{{- end }}

	"github.com/Nivl/go-rest-tools/network/http/httperr"
	"github.com/Nivl/go-rest-tools/storage/db"
	uuid "github.com/satori/go.uuid"
)

{{ if .Generate "JoinSQL" -}}
// Join{{.OptionalName}}SQL returns a string ready to be embed in a JOIN query
func Join{{.OptionalName}}SQL(prefix string) string {
	fields := []string{ {{.FieldsAsArray}} }
	output := ""

	for i, field := range fields {
		if i != 0 {
			output += ", "
		}

		fullName := fmt.Sprintf("%s.%s", prefix, field)
		output += fmt.Sprintf("%s \"%s\"", fullName, fullName)
	}

	return output
}
{{- end }}

{{ if .Generate "Get" -}}
// Get{{.OptionalName}}ByID finds and returns an active {{.ModelNameLC}} by ID
// Deleted object are not returned
func Get{{.OptionalName}}ByID(q db.DB, id string) (*{{.ModelName}}, error) {
	{{.ModelVar}} := &{{.ModelName}}{}
	stmt := "SELECT * from {{.TableName}} WHERE id=$1 and deleted_at IS NULL LIMIT 1"
	err := db.Get(q, {{.ModelVar}}, stmt, id)
	// We want to return nil if a {{.ModelNameLC}} is not found
	if {{.ModelVar}}.ID == "" {
		return nil, err
	}
	return {{.ModelVar}}, err
}
{{- end }}

{{ if .Generate "GetAny" -}}
// GetAny{{.OptionalName}}ByID finds and returns an {{.ModelNameLC}} by ID.
// Deleted object are returned
func GetAny{{.OptionalName}}ByID(q db.DB, id string) (*{{.ModelName}}, error) {
	{{.ModelVar}} := &{{.ModelName}}{}
	stmt := "SELECT * from {{.TableName}} WHERE id=$1 LIMIT 1"
	err := db.Get(q, {{.ModelVar}}, stmt, id)
	// We want to return nil if a {{.ModelNameLC}} is not found
	if {{.ModelVar}}.ID == "" {
		return nil, err
	}
	return {{.ModelVar}}, err
}
{{- end }}

{{ if .Generate "Exists" -}}
// {{.OptionalName}}Exists checks if a {{.ModelNameLC}} exists for a specific ID
func {{.OptionalName}}Exists(q db.DB, id string) (bool, error) {
	exists := false
	stmt := "SELECT exists(SELECT 1 FROM {{.TableName}} WHERE id=$1 and deleted_at IS NULL)"
	err := db.Get(q, &exists, stmt, id)
	return exists, err
}
{{- end }}

{{ if .Generate "Save" -}}
// Save creates or updates the article depending on the value of the id using
// a transaction
func ({{.ModelVar}} *{{.ModelName}}) Save(q db.DB) error {
	if {{.ModelVar}}.ID == "" {
		return {{.ModelVar}}.Create(q)
	}

	return {{.ModelVar}}.Update(q)
}
{{- end }}

{{ if .Generate "Create" -}}
// Create persists a {{.ModelNameLC}} in the database
func ({{.ModelVar}} *{{.ModelName}}) Create(q db.DB) error {
	if {{.ModelVar}}.ID != "" {
		return errors.New("cannot persist a {{.ModelNameLC}} that already has an ID")
	}

	return {{.ModelVar}}.doCreate(q)
}
{{- end }}

{{ if .Generate "doCreate" -}}
// doCreate persists a {{.ModelNameLC}} in the database using a Node
func ({{.ModelVar}} *{{.ModelName}}) doCreate(q db.DB) error {
	if {{.ModelVar}} == nil {
		return errors.New("{{.ModelNameLC}} not instanced")
	}

	{{.ModelVar}}.ID = uuid.NewV4().String()
	{{.ModelVar}}.UpdatedAt = db.Now()
	if {{.ModelVar}}.CreatedAt == nil {
		{{.ModelVar}}.CreatedAt = db.Now()
	}

	stmt := "{{.CreateStmt}}"
	_, err := q.NamedExec(stmt, {{.ModelVar}})

  return httperr.NewFromSQL(err)
}
{{- end }}

{{ if .Generate "Update" -}}
// Update updates most of the fields of a persisted {{.ModelNameLC}}
// Excluded fields are id, created_at, deleted_at, etc.
func ({{.ModelVar}} *{{.ModelName}}) Update(q db.DB) error {
	if {{.ModelVar}}.ID == "" {
		return errors.New("cannot update a non-persisted {{.ModelNameLC}}")
	}

	return {{.ModelVar}}.doUpdate(q)
}
{{- end }}

{{ if .Generate "doUpdate" -}}
// doUpdate updates a {{.ModelNameLC}} in the database
func ({{.ModelVar}} *{{.ModelName}}) doUpdate(q db.DB) error {
	if {{.ModelVar}}.ID == "" {
		return errors.New("cannot update a non-persisted {{.ModelNameLC}}")
	}

	{{.ModelVar}}.UpdatedAt = db.Now()

	stmt := "{{.UpdateStmt}}"
	_, err := q.NamedExec(stmt, {{.ModelVar}})

	return httperr.NewFromSQL(err)
}
{{- end }}

{{ if .Generate "Delete" -}}
// Delete removes a {{.ModelNameLC}} from the database
func ({{.ModelVar}} *{{.ModelName}}) Delete(q db.DB) error {
	if {{.ModelVar}} == nil {
		return errors.New("{{.ModelNameLC}} not instanced")
	}

	if {{.ModelVar}}.ID == "" {
		return errors.New("{{.ModelNameLC}} has not been saved")
	}

	stmt := "DELETE FROM {{.TableName}} WHERE id=$1"
	_, err := q.Exec(stmt, {{.ModelVar}}.ID)

	return err
}
{{- end }}

{{ if .Generate "GetID" -}}
// GetID returns the ID field
func ({{.ModelVar}} *{{.ModelName}}) GetID() string {
	return {{.ModelVar}}.ID
}
{{- end }}

{{ if .Generate "SetID" -}}
// SetID sets the ID field
func ({{.ModelVar}} *{{.ModelName}}) SetID(id string) {
	{{.ModelVar}}.ID = id
}
{{- end }}

{{ if .Generate "IsZero" -}}
// IsZero checks if the object is either nil or don't have an ID
func ({{.ModelVar}} *{{.ModelName}}) IsZero() bool {
	return {{.ModelVar}} == nil || {{.ModelVar}}.ID == ""
}
{{- end }}`
<commit_msg>refactor: Use q.Get() instead of db.Get() for Get*ByID()<commit_after>package generate

var modelTpl = `package {{.PackageName}}

// Code auto-generated; DO NOT EDIT

import (
	"errors"
	{{ if .Generate "JoinSQL" -}}
	"fmt"
	{{- end }}

	"github.com/Nivl/go-rest-tools/types/apierror"
	"github.com/Nivl/go-rest-tools/storage/db"
	uuid "github.com/satori/go.uuid"
)

{{ if .Generate "JoinSQL" -}}
// Join{{.OptionalName}}SQL returns a string ready to be embed in a JOIN query
func Join{{.OptionalName}}SQL(prefix string) string {
	fields := []string{ {{.FieldsAsArray}} }
	output := ""

	for i, field := range fields {
		if i != 0 {
			output += ", "
		}

		fullName := fmt.Sprintf("%s.%s", prefix, field)
		output += fmt.Sprintf("%s \"%s\"", fullName, fullName)
	}

	return output
}
{{- end }}

{{ if .Generate "Get" -}}
// Get{{.OptionalName}}ByID finds and returns an active {{.ModelNameLC}} by ID
// Deleted object are not returned
func Get{{.OptionalName}}ByID(q db.DB, id string) (*{{.ModelName}}, error) {
	{{.ModelVar}} := &{{.ModelName}}{}
	stmt := "SELECT * from {{.TableName}} WHERE id=$1 and deleted_at IS NULL LIMIT 1"
	err := q.Get({{.ModelVar}}, stmt, id)
	return {{.ModelVar}}, apierror.NewFromSQL(err)
}
{{- end }}

{{ if .Generate "GetAny" -}}
// GetAny{{.OptionalName}}ByID finds and returns an {{.ModelNameLC}} by ID.
// Deleted object are returned
func GetAny{{.OptionalName}}ByID(q db.DB, id string) (*{{.ModelName}}, error) {
	{{.ModelVar}} := &{{.ModelName}}{}
	stmt := "SELECT * from {{.TableName}} WHERE id=$1 LIMIT 1"
	err := q.Get({{.ModelVar}}, stmt, id)
	return {{.ModelVar}}, apierror.NewFromSQL(err)
}
{{- end }}

{{ if .Generate "Exists" -}}
// {{.OptionalName}}Exists checks if a {{.ModelNameLC}} exists for a specific ID
func {{.OptionalName}}Exists(q db.DB, id string) (bool, error) {
	exists := false
	stmt := "SELECT exists(SELECT 1 FROM {{.TableName}} WHERE id=$1 and deleted_at IS NULL)"
	err := db.Get(q, &exists, stmt, id)
	return exists, err
}
{{- end }}

{{ if .Generate "Save" -}}
// Save creates or updates the article depending on the value of the id using
// a transaction
func ({{.ModelVar}} *{{.ModelName}}) Save(q db.DB) error {
	if {{.ModelVar}}.ID == "" {
		return {{.ModelVar}}.Create(q)
	}

	return {{.ModelVar}}.Update(q)
}
{{- end }}

{{ if .Generate "Create" -}}
// Create persists a {{.ModelNameLC}} in the database
func ({{.ModelVar}} *{{.ModelName}}) Create(q db.DB) error {
	if {{.ModelVar}}.ID != "" {
		return errors.New("cannot persist a {{.ModelNameLC}} that already has an ID")
	}

	return {{.ModelVar}}.doCreate(q)
}
{{- end }}

{{ if .Generate "doCreate" -}}
// doCreate persists a {{.ModelNameLC}} in the database using a Node
func ({{.ModelVar}} *{{.ModelName}}) doCreate(q db.DB) error {
	if {{.ModelVar}} == nil {
		return errors.New("{{.ModelNameLC}} not instanced")
	}

	{{.ModelVar}}.ID = uuid.NewV4().String()
	{{.ModelVar}}.UpdatedAt = db.Now()
	if {{.ModelVar}}.CreatedAt == nil {
		{{.ModelVar}}.CreatedAt = db.Now()
	}

	stmt := "{{.CreateStmt}}"
	_, err := q.NamedExec(stmt, {{.ModelVar}})

  return apierror.NewFromSQL(err)
}
{{- end }}

{{ if .Generate "Update" -}}
// Update updates most of the fields of a persisted {{.ModelNameLC}}
// Excluded fields are id, created_at, deleted_at, etc.
func ({{.ModelVar}} *{{.ModelName}}) Update(q db.DB) error {
	if {{.ModelVar}}.ID == "" {
		return errors.New("cannot update a non-persisted {{.ModelNameLC}}")
	}

	return {{.ModelVar}}.doUpdate(q)
}
{{- end }}

{{ if .Generate "doUpdate" -}}
// doUpdate updates a {{.ModelNameLC}} in the database
func ({{.ModelVar}} *{{.ModelName}}) doUpdate(q db.DB) error {
	if {{.ModelVar}}.ID == "" {
		return errors.New("cannot update a non-persisted {{.ModelNameLC}}")
	}

	{{.ModelVar}}.UpdatedAt = db.Now()

	stmt := "{{.UpdateStmt}}"
	_, err := q.NamedExec(stmt, {{.ModelVar}})

	return apierror.NewFromSQL(err)
}
{{- end }}

{{ if .Generate "Delete" -}}
// Delete removes a {{.ModelNameLC}} from the database
func ({{.ModelVar}} *{{.ModelName}}) Delete(q db.DB) error {
	if {{.ModelVar}} == nil {
		return errors.New("{{.ModelNameLC}} not instanced")
	}

	if {{.ModelVar}}.ID == "" {
		return errors.New("{{.ModelNameLC}} has not been saved")
	}

	stmt := "DELETE FROM {{.TableName}} WHERE id=$1"
	_, err := q.Exec(stmt, {{.ModelVar}}.ID)

	return err
}
{{- end }}

{{ if .Generate "GetID" -}}
// GetID returns the ID field
func ({{.ModelVar}} *{{.ModelName}}) GetID() string {
	return {{.ModelVar}}.ID
}
{{- end }}

{{ if .Generate "SetID" -}}
// SetID sets the ID field
func ({{.ModelVar}} *{{.ModelName}}) SetID(id string) {
	{{.ModelVar}}.ID = id
}
{{- end }}

{{ if .Generate "IsZero" -}}
// IsZero checks if the object is either nil or don't have an ID
func ({{.ModelVar}} *{{.ModelName}}) IsZero() bool {
	return {{.ModelVar}} == nil || {{.ModelVar}}.ID == ""
}
{{- end }}`
<|endoftext|>