<commit_before>package main

// The Cgo directives must immediately preceed 'import "C"' below.
// Example:
//   $ wget http://.../web100_userland-1.8.tar.gz
//   $ tar -xvf web100_userland-1.8.tar.gz
//   $ pushd web100_userland
//   $ ./configure --prefix=$PWD/build
//   $ make && make install
//   $ popd
//   $ go build

/*
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <web100.h>
#include <web100-int.h>

web100_log *get_null_log() {
	return NULL;
}
*/
import "C"

import (
	"fmt"
	"unsafe"
)

// Necessary web100 functions:
//  + web100_log_open_read(filename)
//  + web100_log_close_read(log_)
//
//   ConvertWeb100VarToNameValue(snap_, var, &var_name, &var_value)
//   for (web100_var *var = web100_var_head(group_);
//        var != NULL;
//        var = web100_var_next(var)) {
//
//   web100_get_log_agent(log_)
//   web100_get_log_time(log_);
//   web100_get_log_group(log_);
//
//   connection_ = web100_get_log_connection(log_);
//   snap_ = web100_snapshot_alloc_from_log(log_);
//   web100_snap_from_log(snap_, log_)
//

// Go structs cannot embed fields with C types.
// https://golang.org/cmd/cgo/#hdr-Go_references_to_C
// Discovered:
//  - 'NULL' is usually equivalent to 'nil'

type Web100 struct {
	log unsafe.Pointer
}

func Open(filename string) (*Web100, error) {
	w := &Web100{}
	var log *C.web100_log

	c_filename := C.CString(filename)
	defer C.free(unsafe.Pointer(c_filename))

	log = C.web100_log_open_read(c_filename)
	fmt.Println("errno", C.web100_errno)
	if log == nil {
		return nil, fmt.Errorf(C.GoString(C.web100_strerror(C.web100_errno)))
	}
	w.log = unsafe.Pointer(log)
	fmt.Println(log)
	snap := C.web100_snapshot_alloc_from_log(log)
	defer C.web100_snapshot_free(snap)
	return w, nil
}

func (w *Web100) Read() error {
	var log *C.web100_log
	var snap *C.web100_snapshot

	log = (*C.web100_log)(w.log)
	fmt.Println("test")
	fmt.Println(log)
	snap = C.web100_snapshot_alloc_from_log(log)
	defer C.web100_snapshot_free(snap)

	err := C.web100_snap_from_log(snap, log)
	if err != C.WEB100_ERR_SUCCESS {
		return fmt.Errorf(C.GoString(C.web100_strerror(C.int(err))))
	}

	group := C.web100_get_log_group(log)
	for v := C.web100_var_head(group); v != nil; v = C.web100_var_next(v) {
		//name := C.web100_get_var_name(v)
		var_size := C.web100_get_var_size(v)
		var_type := C.web100_get_var_type(v)

		var_value := C.malloc(var_size)
		var_text := C.malloc(2 * C.WEB100_VALUE_LEN_MAX) // Use a better size.

		err := C.web100_snap_read(v, snap, var_value)
		if err != C.WEB100_ERR_SUCCESS {
			return fmt.Errorf(C.GoString(C.web100_strerror(C.int(err))))
		}
		C.web100_value_to_textn((*C.char)(var_text), var_size, (C.WEB100_TYPE)(var_type), var_value)
		//fmt.Println(
		//	C.GoString(name),
		//	var_size,
		//	var_type,
		//	C.GoString((*C.char)(var_value)),
		//	C.GoString((*C.char)(var_text)))
	}

	return nil
}

func (w *Web100) Close() error {
	var log *C.web100_log

	log = (*C.web100_log)(w.log)
	err := C.web100_log_close_read(log)
	if err != C.WEB100_ERR_SUCCESS {
		return fmt.Errorf(C.GoString(C.web100_strerror(C.int(err))))
	}

	// Clear pointer after free.
	w.log = nil
	return nil
}

func LookupError(errnum int) string {
	return C.GoString(C.web100_strerror(C.int(errnum)))
}

func main() {
	fmt.Println(LookupError(0))
	// fmt.Println(LookupError(1))
	// fmt.Println(LookupError(2))
	// fmt.Println(LookupError(3))
	// w, err := Open("logs/20170413T01:05:24.133980000Z_c-68-80-50-142.hsd1.pa.comcast.net:53301.s2c_snaplog")
	w, err := Open("logs/20170413T01:05:56.356778000Z_c-76-19-153-197.hsd1.ma.comcast.net:54741.c2s_snaplog")
	if err != nil {
		panic(err)
	}
	err = w.Read()
	if err != nil {
		panic(err)
	}
	fmt.Printf("%#v\n", w)
	w.Close()
	fmt.Printf("%#v\n", w)
}
<commit_msg>Add flag.<commit_after>package main

// The Cgo directives must immediately preceed 'import "C"' below.
// Example:
//   $ wget http://.../web100_userland-1.8.tar.gz
//   $ tar -xvf web100_userland-1.8.tar.gz
//   $ pushd web100_userland
//   $ ./configure --prefix=$PWD/build
//   $ make && make install
//   $ popd
//   $ go build

/*
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <web100.h>
#include <web100-int.h>

web100_log *get_null_log() {
	return NULL;
}
*/
import "C"

import (
	"flag"
	"fmt"
	"unsafe"
)

var (
	filename = flag.String("filename", "", "Trace filename.")
)

// Necessary web100 functions:
//  + web100_log_open_read(filename)
//  + web100_log_close_read(log_)
//
//   ConvertWeb100VarToNameValue(snap_, var, &var_name, &var_value)
//   for (web100_var *var = web100_var_head(group_);
//        var != NULL;
//        var = web100_var_next(var)) {
//
//   web100_get_log_agent(log_)
//   web100_get_log_time(log_);
//   web100_get_log_group(log_);
//
//   connection_ = web100_get_log_connection(log_);
//   snap_ = web100_snapshot_alloc_from_log(log_);
//   web100_snap_from_log(snap_, log_)
//

// Go structs cannot embed fields with C types.
// https://golang.org/cmd/cgo/#hdr-Go_references_to_C
// Discovered:
//  - 'NULL' is usually equivalent to 'nil'

type Web100 struct {
	log unsafe.Pointer
}

func Open(filename string) (*Web100, error) {
	w := &Web100{}
	var log *C.web100_log

	c_filename := C.CString(filename)
	defer C.free(unsafe.Pointer(c_filename))

	log = C.web100_log_open_read(c_filename)
	fmt.Println("errno", C.web100_errno)
	if log == nil {
		return nil, fmt.Errorf(C.GoString(C.web100_strerror(C.web100_errno)))
	}
	w.log = unsafe.Pointer(log)
	fmt.Println(log)
	snap := C.web100_snapshot_alloc_from_log(log)
	defer C.web100_snapshot_free(snap)
	return w, nil
}

func (w *Web100) Read() error {
	var log *C.web100_log
	var snap *C.web100_snapshot

	log = (*C.web100_log)(w.log)
	fmt.Println("test")
	fmt.Println(log)
	snap = C.web100_snapshot_alloc_from_log(log)
	defer C.web100_snapshot_free(snap)

	err := C.web100_snap_from_log(snap, log)
	if err != C.WEB100_ERR_SUCCESS {
		return fmt.Errorf(C.GoString(C.web100_strerror(C.int(err))))
	}

	group := C.web100_get_log_group(log)
	for v := C.web100_var_head(group); v != nil; v = C.web100_var_next(v) {
		//name := C.web100_get_var_name(v)
		var_size := C.web100_get_var_size(v)
		var_type := C.web100_get_var_type(v)

		var_value := C.malloc(var_size)
		var_text := C.malloc(2 * C.WEB100_VALUE_LEN_MAX) // Use a better size.

		err := C.web100_snap_read(v, snap, var_value)
		if err != C.WEB100_ERR_SUCCESS {
			return fmt.Errorf(C.GoString(C.web100_strerror(C.int(err))))
		}
		C.web100_value_to_textn((*C.char)(var_text), var_size, (C.WEB100_TYPE)(var_type), var_value)
		//fmt.Println(
		//	C.GoString(name),
		//	var_size,
		//	var_type,
		//	C.GoString((*C.char)(var_value)),
		//	C.GoString((*C.char)(var_text)))
	}

	return nil
}

func (w *Web100) Close() error {
	var log *C.web100_log

	log = (*C.web100_log)(w.log)
	err := C.web100_log_close_read(log)
	if err != C.WEB100_ERR_SUCCESS {
		return fmt.Errorf(C.GoString(C.web100_strerror(C.int(err))))
	}

	// Clear pointer after free.
	w.log = nil
	return nil
}

func LookupError(errnum int) string {
	return C.GoString(C.web100_strerror(C.int(errnum)))
}

func main() {
	flag.Parse()

	fmt.Println(LookupError(0))
	// fmt.Println(LookupError(1))
	// fmt.Println(LookupError(2))
	// fmt.Println(LookupError(3))
	// w, err := Open("logs/20170413T01:05:24.133980000Z_c-68-80-50-142.hsd1.pa.comcast.net:53301.s2c_snaplog")
	w, err := Open(*filename)
	if err != nil {
		panic(err)
	}
	err = w.Read()
	if err != nil {
		panic(err)
	}
	fmt.Printf("%#v\n", w)
	w.Close()
	fmt.Printf("%#v\n", w)
}
<|endoftext|>


<commit_before>//  Copyright (c) 2013 Couchbase, Inc.
//  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 xpipeline

import (
	"log"

	"github.com/couchbaselabs/tuqtng/ast"
)

type Project struct {
	Source      Operator
	itemChannel ast.ItemChannel
	Result      ast.ResultExpressionList
}

func NewProject(result ast.ResultExpressionList) *Project {
	return &Project{
		Result:      result,
		itemChannel: make(ast.ItemChannel),
	}
}

func (this *Project) SetSource(source Operator) {
	this.Source = source
}

func (this *Project) GetItemChannel() ast.ItemChannel {
	return this.itemChannel
}

func (this *Project) Run() {
	defer close(this.itemChannel)

	// start the source
	go this.Source.Run()
	for item := range this.Source.GetItemChannel() {

		resultMap := map[string]ast.Value{}
		for _, resultItem := range this.Result {
			if resultItem.Star {
				if resultItem.Expr != nil {
					// evaluate this expression first
					val, err := resultItem.Expr.Evaluate(item)
					if err == nil {
						switch val := val.(type) {
						case map[string]ast.Value:
							// then if the result was an object
							// add its contents ot the result map
							for k, v := range val {
								resultMap[k] = v
							}
						}
					} else {
						log.Fatal("unexpected err: %v", err)
					}
				} else {
					// just a star, take all the contents of the source item
					// and add them to the result item
					topLevelKeys := item.GetTopLevelKeys()
					for _, key := range topLevelKeys {
						val, err := item.GetPath(key)
						if err == nil {
							resultMap[key] = val
						} else {
							log.Fatal("unexpected err: %v", err)
						}
					}
				}
			} else if resultItem.Expr != nil {
				// evaluate the expression
				val, err := resultItem.Expr.Evaluate(item)
				if err == nil {
					resultMap[resultItem.As] = val
				} else {
					log.Fatal("unexpected err: %v", err)
				}
			}
		}

		// create the actual result Item
		finalItem := ast.NewMapItem(resultMap, item.GetMeta())

		// write this to the output
		this.itemChannel <- finalItem
	}
}
<commit_msg>fix issues identified by go vet<commit_after>//  Copyright (c) 2013 Couchbase, Inc.
//  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 xpipeline

import (
	"log"

	"github.com/couchbaselabs/tuqtng/ast"
)

type Project struct {
	Source      Operator
	itemChannel ast.ItemChannel
	Result      ast.ResultExpressionList
}

func NewProject(result ast.ResultExpressionList) *Project {
	return &Project{
		Result:      result,
		itemChannel: make(ast.ItemChannel),
	}
}

func (this *Project) SetSource(source Operator) {
	this.Source = source
}

func (this *Project) GetItemChannel() ast.ItemChannel {
	return this.itemChannel
}

func (this *Project) Run() {
	defer close(this.itemChannel)

	// start the source
	go this.Source.Run()
	for item := range this.Source.GetItemChannel() {

		resultMap := map[string]ast.Value{}
		for _, resultItem := range this.Result {
			if resultItem.Star {
				if resultItem.Expr != nil {
					// evaluate this expression first
					val, err := resultItem.Expr.Evaluate(item)
					if err == nil {
						switch val := val.(type) {
						case map[string]ast.Value:
							// then if the result was an object
							// add its contents ot the result map
							for k, v := range val {
								resultMap[k] = v
							}
						}
					} else {
						log.Fatalf("unexpected err: %v", err)
					}
				} else {
					// just a star, take all the contents of the source item
					// and add them to the result item
					topLevelKeys := item.GetTopLevelKeys()
					for _, key := range topLevelKeys {
						val, err := item.GetPath(key)
						if err == nil {
							resultMap[key] = val
						} else {
							log.Fatalf("unexpected err: %v", err)
						}
					}
				}
			} else if resultItem.Expr != nil {
				// evaluate the expression
				val, err := resultItem.Expr.Evaluate(item)
				if err == nil {
					resultMap[resultItem.As] = val
				} else {
					log.Fatalf("unexpected err: %v", err)
				}
			}
		}

		// create the actual result Item
		finalItem := ast.NewMapItem(resultMap, item.GetMeta())

		// write this to the output
		this.itemChannel <- finalItem
	}
}
<|endoftext|>


<commit_before>package memberlist

import (
	"bytes"
	"reflect"
	"testing"
)

func TestPKCS7(t *testing.T) {
	for i := 0; i <= 255; i++ {
		// Make a buffer of size i
		buf := []byte{}
		for j := 0; j < i; j++ {
			buf = append(buf, byte(i))
		}

		// Copy to bytes buffer
		inp := bytes.NewBuffer(nil)
		inp.Write(buf)

		// Pad this out
		pkcs7encode(inp, 0, 16)

		// Unpad
		dec := pkcs7decode(inp.Bytes(), 16)

		// Ensure equivilence
		if !reflect.DeepEqual(buf, dec) {
			t.Fatalf("mismatch: %v %v", buf, dec)
		}
	}

}

func TestEncryptDecrypt_V0(t *testing.T) {
	encryptDecryptVersioned(0, t)
}

func TestEncryptDecrypt_V1(t *testing.T) {
	encryptDecryptVersioned(1, t)
}

func encryptDecryptVersioned(vsn encryptionVersion, t *testing.T) {
	k1 := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
	plaintext := []byte("this is a plain text message")
	extra := []byte("random data")

	var buf bytes.Buffer
	err := encryptPayload(vsn, k1, plaintext, extra, &buf)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	expLen := encryptedLength(vsn, len(plaintext))
	if buf.Len() != expLen {
		t.Fatalf("output length is unexpected %d %d %d", len(plaintext), buf.Len(), expLen)
	}

	msg, err := decryptPayload([][]byte{k1}, buf.Bytes(), extra)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	cmp := bytes.Compare(msg, plaintext)
	if cmp != 0 {
		t.Errorf("len %d %v", len(msg), msg)
		t.Errorf("len %d %v", len(plaintext), plaintext)
		t.Fatalf("encrypt/decrypt failed! %d '%s' '%s'", cmp, msg, plaintext)
	}

}
<commit_msg>Added test for decrypting success when the first key doesn't match.<commit_after>package memberlist

import (
	"bytes"
	"reflect"
	"testing"
)

func TestPKCS7(t *testing.T) {
	for i := 0; i <= 255; i++ {
		// Make a buffer of size i
		buf := []byte{}
		for j := 0; j < i; j++ {
			buf = append(buf, byte(i))
		}

		// Copy to bytes buffer
		inp := bytes.NewBuffer(nil)
		inp.Write(buf)

		// Pad this out
		pkcs7encode(inp, 0, 16)

		// Unpad
		dec := pkcs7decode(inp.Bytes(), 16)

		// Ensure equivilence
		if !reflect.DeepEqual(buf, dec) {
			t.Fatalf("mismatch: %v %v", buf, dec)
		}
	}

}

func TestEncryptDecrypt_V0(t *testing.T) {
	encryptDecryptVersioned(0, t)
}

func TestEncryptDecrypt_V1(t *testing.T) {
	encryptDecryptVersioned(1, t)
}

func encryptDecryptVersioned(vsn encryptionVersion, t *testing.T) {
	k1 := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
	plaintext := []byte("this is a plain text message")
	extra := []byte("random data")

	var buf bytes.Buffer
	err := encryptPayload(vsn, k1, plaintext, extra, &buf)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	expLen := encryptedLength(vsn, len(plaintext))
	if buf.Len() != expLen {
		t.Fatalf("output length is unexpected %d %d %d", len(plaintext), buf.Len(), expLen)
	}

	msg, err := decryptPayload([][]byte{k1}, buf.Bytes(), extra)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	cmp := bytes.Compare(msg, plaintext)
	if cmp != 0 {
		t.Errorf("len %d %v", len(msg), msg)
		t.Errorf("len %d %v", len(plaintext), plaintext)
		t.Fatalf("encrypt/decrypt failed! %d '%s' '%s'", cmp, msg, plaintext)
	}
}

func TestDecryptMultipleKeys(t *testing.T) {
	plaintext := []byte("this is a plain text message")
	extra := []byte("random data")
	keys := [][]byte{
		[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
		[]byte{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
	}

	var buf bytes.Buffer
	err := encryptPayload(1, keys[1], plaintext, extra, &buf)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	msg, err := decryptPayload(keys, buf.Bytes(), extra)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if !bytes.Equal(msg, plaintext) {
		t.Fatalf("bad: %v", msg)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package sensor provides sensor events from various movement sensors.
package sensor

import (
	"errors"
	"sync"
	"time"
)

// Type represents a sensor type.
type Type int

var sensorNames = map[Type]string{
	Accelerometer: "Accelerometer",
	Gyroscope:     "Gyrsocope",
	Magnetometer:  "Magnetometer",
}

// String returns the string representation of the sensor type.
func (t Type) String() string {
	if n, ok := sensorNames[t]; ok {
		return n
	}
	return "Unknown sensor"
}

var (
	Accelerometer = Type(0)
	Gyroscope     = Type(1)
	Magnetometer  = Type(2)
)

// Event represents a sensor event.
type Event struct {
	// Sensor is the type of the sensor the event is coming from.
	Sensor Type

	// Timestamp is a device specific event time in nanoseconds.
	// Timestamps are not Unix times, they represent a time that is
	// only valid for the device's default sensor.
	Timestamp int64

	// Data is the event data.
	//
	// If the event source is Accelerometer,
	//  - Data[0]: acceleration force in x axis in m/s^2
	//  - Data[1]: acceleration force in y axis in m/s^2
	//  - Data[2]: acceleration force in z axis in m/s^2
	//
	// If the event source is Gyroscope,
	//  - Data[0]: rate of rotation around the x axis in rad/s
	//  - Data[1]: rate of rotation around the y axis in rad/s
	//  - Data[2]: rate of rotation around the z axis in rad/s
	//
	// If the event source is Magnetometer,
	//  - Data[0]: force of gravity along the x axis in m/s^2
	//  - Data[1]: force of gravity along the y axis in m/s^2
	//  - Data[2]: force of gravity along the z axis in m/s^2
	//
	Data []float64
}

// Manager multiplexes sensor event data from various sensor sources.
type Manager struct {
	once sync.Once
	m    *manager // platform-specific implementation of the underlying manager
}

func (m *Manager) init() {
	m.m = &manager{}
}

// Enable enables a sensor with the specified delay rate.
// If there are multiple sensors of type t on the device, Enable uses
// the default one.
// If there is no default sensor of type t on the device, an error returned.
// Valid sensor types supported by this package are Accelerometer,
// Gyroscope, Magnetometer and Altimeter.
func (m *Manager) Enable(t Type, delay time.Duration) error {
	m.once.Do(m.init)
	if t < 0 || int(t) >= len(sensorNames) {
		return errors.New("sensor: unknown sensor type")
	}
	return enable(m.m, t, delay)
}

// Disable disables to feed the manager with the specified sensor.
func (m *Manager) Disable(t Type) error {
	m.once.Do(m.init)
	if t < 0 || int(t) >= len(sensorNames) {
		return errors.New("sensor: unknown sensor type")
	}
	return disable(m.m, t)
}

// Read reads a series of events from the manager.
// It may read up to len(e) number of events, but will return
// less events if timeout occurs.
func (m *Manager) Read(e []Event) (n int, err error) {
	m.once.Do(m.init)
	return read(m.m, e)
}

// Close stops the manager and frees the related resources.
// Once Close is called, Manager becomes invalid to use.
func (m *Manager) Close() error {
	m.once.Do(m.init)
	return close(m.m)
}
<commit_msg>mobile/sensor: remove the unnecessary init mutex<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package sensor provides sensor events from various movement sensors.
package sensor

import (
	"errors"
	"time"
)

// Type represents a sensor type.
type Type int

var sensorNames = map[Type]string{
	Accelerometer: "Accelerometer",
	Gyroscope:     "Gyrsocope",
	Magnetometer:  "Magnetometer",
}

// String returns the string representation of the sensor type.
func (t Type) String() string {
	if n, ok := sensorNames[t]; ok {
		return n
	}
	return "Unknown sensor"
}

var (
	Accelerometer = Type(0)
	Gyroscope     = Type(1)
	Magnetometer  = Type(2)
)

// Event represents a sensor event.
type Event struct {
	// Sensor is the type of the sensor the event is coming from.
	Sensor Type

	// Timestamp is a device specific event time in nanoseconds.
	// Timestamps are not Unix times, they represent a time that is
	// only valid for the device's default sensor.
	Timestamp int64

	// Data is the event data.
	//
	// If the event source is Accelerometer,
	//  - Data[0]: acceleration force in x axis in m/s^2
	//  - Data[1]: acceleration force in y axis in m/s^2
	//  - Data[2]: acceleration force in z axis in m/s^2
	//
	// If the event source is Gyroscope,
	//  - Data[0]: rate of rotation around the x axis in rad/s
	//  - Data[1]: rate of rotation around the y axis in rad/s
	//  - Data[2]: rate of rotation around the z axis in rad/s
	//
	// If the event source is Magnetometer,
	//  - Data[0]: force of gravity along the x axis in m/s^2
	//  - Data[1]: force of gravity along the y axis in m/s^2
	//  - Data[2]: force of gravity along the z axis in m/s^2
	//
	Data []float64
}

// Manager multiplexes sensor event data from various sensor sources.
type Manager struct {
	m *manager // platform-specific implementation of the underlying manager
}

// Enable enables a sensor with the specified delay rate.
// If there are multiple sensors of type t on the device, Enable uses
// the default one.
// If there is no default sensor of type t on the device, an error returned.
// Valid sensor types supported by this package are Accelerometer,
// Gyroscope, Magnetometer and Altimeter.
func (m *Manager) Enable(t Type, delay time.Duration) error {
	if m.m == nil {
		m.m = new(manager)
	}
	if t < 0 || int(t) >= len(sensorNames) {
		return errors.New("sensor: unknown sensor type")
	}
	return enable(m.m, t, delay)
}

// Disable disables to feed the manager with the specified sensor.
func (m *Manager) Disable(t Type) error {
	if m.m == nil {
		m.m = new(manager)
	}
	if t < 0 || int(t) >= len(sensorNames) {
		return errors.New("sensor: unknown sensor type")
	}
	return disable(m.m, t)
}

// Read reads a series of events from the manager.
// It may read up to len(e) number of events, but will return
// less events if timeout occurs.
func (m *Manager) Read(e []Event) (n int, err error) {
	if m.m == nil {
		m.m = new(manager)
	}
	return read(m.m, e)
}

// Close stops the manager and frees the related resources.
// Once Close is called, Manager becomes invalid to use.
func (m *Manager) Close() error {
	if m.m == nil {
		m.m = new(manager)
	}
	return close(m.m)
}
<|endoftext|>


<commit_before>package nmea

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

var sentencetests = []struct {
	name string
	raw  string
	err  string
	sent BaseSentence
}{
	{
		name: "checksum ok",
		raw:  "$GPFOO,1,2,3.3,x,y,zz,*51",
		sent: BaseSentence{
			Talker:   "GP",
			Type:     "FOO",
			Fields:   []string{"1", "2", "3.3", "x", "y", "zz", ""},
			Checksum: "51",
			Raw:      "$GPFOO,1,2,3.3,x,y,zz,*51",
		},
	},
	{
		name: "good parsing",
		raw:  "$GPRMC,235236,A,3925.9479,N,11945.9211,W,44.7,153.6,250905,15.2,E,A*0C",
		sent: BaseSentence{
			Talker:   "GP",
			Type:     "RMC",
			Fields:   []string{"235236", "A", "3925.9479", "N", "11945.9211", "W", "44.7", "153.6", "250905", "15.2", "E", "A"},
			Checksum: "0C",
			Raw:      "$GPRMC,235236,A,3925.9479,N,11945.9211,W,44.7,153.6,250905,15.2,E,A*0C",
		},
	},
	{
		name: "checksum bad",
		raw:  "$GPFOO,1,2,3.4,x,y,zz,*51",
		err:  "nmea: sentence checksum mismatch [56 != 51]",
	},
	{
		name: "bad start character",
		raw:  "%GPFOO,1,2,3,x,y,z*1A",
		err:  "nmea: sentence does not start with a '$'",
	},
	{
		name: "bad checksum delimiter",
		raw:  "$GPFOO,1,2,3,x,y,z",
		err:  "nmea: sentence does not contain checksum separator",
	},
	{
		name: "no start delimiter",
		raw:  "abc$GPRMC,235236,A,3925.9479,N,11945.9211,W,44.7,153.6,250905,15.2,E,A*0C",
		err:  "nmea: sentence does not start with a '$'",
	},
	{
		name: "no contain delimiter",
		raw:  "GPRMC,235236,A,3925.9479,N,11945.9211,W,44.7,153.6,250905,15.2,E,A*0C",
		err:  "nmea: sentence does not start with a '$'",
	},
	{
		name: "another bad checksum",
		raw:  "$GPRMC,235236,A,3925.9479,N,11945.9211,W,44.7,153.6,250905,15.2,E,A*0A",
		err:  "nmea: sentence checksum mismatch [0C != 0A]",
	},
}

func TestSentences(t *testing.T) {
	for _, tt := range sentencetests {
		t.Run(tt.name, func(t *testing.T) {
			sent, err := parseSentence(tt.raw)
			if tt.err != "" {
				assert.EqualError(t, err, tt.err)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.sent, sent)
				assert.Equal(t, tt.sent.Raw, sent.String())
			}
		})
	}
}

var parsetests = []struct {
	name string
	raw  string
	err  string
	msg  interface{}
}{
	{
		name: "bad sentence",
		raw:  "SDFSD,2340dfmswd",
		err:  "nmea: sentence does not start with a '$'",
	},
	{
		name: "bad sentence type",
		raw:  "$INVALID,123,123,*7D",
		err:  "nmea: sentence prefix 'INVALID' not supported",
	},
}

func TestParse(t *testing.T) {
	for _, tt := range parsetests {
		t.Run(tt.name, func(t *testing.T) {
			m, err := Parse(tt.raw)
			if tt.err != "" {
				assert.EqualError(t, err, tt.err)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.msg, m)
			}
		})
	}
}
<commit_msg>add parsePrefix tests<commit_after>package nmea

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

var sentencetests = []struct {
	name string
	raw  string
	err  string
	sent BaseSentence
}{
	{
		name: "checksum ok",
		raw:  "$GPFOO,1,2,3.3,x,y,zz,*51",
		sent: BaseSentence{
			Talker:   "GP",
			Type:     "FOO",
			Fields:   []string{"1", "2", "3.3", "x", "y", "zz", ""},
			Checksum: "51",
			Raw:      "$GPFOO,1,2,3.3,x,y,zz,*51",
		},
	},
	{
		name: "good parsing",
		raw:  "$GPRMC,235236,A,3925.9479,N,11945.9211,W,44.7,153.6,250905,15.2,E,A*0C",
		sent: BaseSentence{
			Talker:   "GP",
			Type:     "RMC",
			Fields:   []string{"235236", "A", "3925.9479", "N", "11945.9211", "W", "44.7", "153.6", "250905", "15.2", "E", "A"},
			Checksum: "0C",
			Raw:      "$GPRMC,235236,A,3925.9479,N,11945.9211,W,44.7,153.6,250905,15.2,E,A*0C",
		},
	},
	{
		name: "checksum bad",
		raw:  "$GPFOO,1,2,3.4,x,y,zz,*51",
		err:  "nmea: sentence checksum mismatch [56 != 51]",
	},
	{
		name: "bad start character",
		raw:  "%GPFOO,1,2,3,x,y,z*1A",
		err:  "nmea: sentence does not start with a '$'",
	},
	{
		name: "bad checksum delimiter",
		raw:  "$GPFOO,1,2,3,x,y,z",
		err:  "nmea: sentence does not contain checksum separator",
	},
	{
		name: "no start delimiter",
		raw:  "abc$GPRMC,235236,A,3925.9479,N,11945.9211,W,44.7,153.6,250905,15.2,E,A*0C",
		err:  "nmea: sentence does not start with a '$'",
	},
	{
		name: "no contain delimiter",
		raw:  "GPRMC,235236,A,3925.9479,N,11945.9211,W,44.7,153.6,250905,15.2,E,A*0C",
		err:  "nmea: sentence does not start with a '$'",
	},
	{
		name: "another bad checksum",
		raw:  "$GPRMC,235236,A,3925.9479,N,11945.9211,W,44.7,153.6,250905,15.2,E,A*0A",
		err:  "nmea: sentence checksum mismatch [0C != 0A]",
	},
}

func TestSentences(t *testing.T) {
	for _, tt := range sentencetests {
		t.Run(tt.name, func(t *testing.T) {
			sent, err := parseSentence(tt.raw)
			if tt.err != "" {
				assert.EqualError(t, err, tt.err)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.sent, sent)
				assert.Equal(t, tt.sent.Raw, sent.String())
			}
		})
	}
}

var prefixtests = []struct {
	name   string
	prefix string
	talker string
	typ    string
}{
	{
		name:   "normal prefix",
		prefix: "GPRMC",
		talker: "GP",
		typ:    "RMC",
	},
	{
		name:   "missing type",
		prefix: "GP",
		talker: "GP",
		typ:    "",
	},
	{
		name:   "one character",
		prefix: "X",
		talker: "X",
		typ:    "",
	},
	{
		name:   "proprietary talker",
		prefix: "PGRME",
		talker: "P",
		typ:    "GRME",
	},
	{
		name:   "short proprietary talker",
		prefix: "PX",
		talker: "P",
		typ:    "X",
	},
}

func TestPrefix(t *testing.T) {
	for _, tt := range prefixtests {
		t.Run(tt.name, func(t *testing.T) {
			talker, typ := parsePrefix(tt.prefix)
			assert.Equal(t, tt.talker, talker)
			assert.Equal(t, tt.typ, typ)
		})
	}
}

var parsetests = []struct {
	name string
	raw  string
	err  string
	msg  interface{}
}{
	{
		name: "bad sentence",
		raw:  "SDFSD,2340dfmswd",
		err:  "nmea: sentence does not start with a '$'",
	},
	{
		name: "bad sentence type",
		raw:  "$INVALID,123,123,*7D",
		err:  "nmea: sentence prefix 'INVALID' not supported",
	},
}

func TestParse(t *testing.T) {
	for _, tt := range parsetests {
		t.Run(tt.name, func(t *testing.T) {
			m, err := Parse(tt.raw)
			if tt.err != "" {
				assert.EqualError(t, err, tt.err)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.msg, m)
			}
		})
	}
}
<|endoftext|>


<commit_before>/**
 *  Copyright 2014 Paul Querna
 *
 *  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 ffjsoninception

import (
	"fmt"
	"github.com/pquerna/ffjson/pills"
	"reflect"
)

func typeInInception(ic *Inception, typ reflect.Type) bool {
	for _, v := range ic.objs {
		if v.Typ == typ {
			return true
		}
	}

	return false
}

func getOmitEmpty(ic *Inception, sf *StructField) string {
	switch sf.Typ.Kind() {

	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return "if len(mj." + sf.Name + ") != 0 {" + "\n"

	case reflect.Int,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64,
		reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64,
		reflect.Uintptr,
		reflect.Float32,
		reflect.Float64:
		return "if mj." + sf.Name + " != 0 {" + "\n"

	case reflect.Bool:
		return "if mj." + sf.Name + " != false {" + "\n"

	case reflect.Interface, reflect.Ptr:
		// TODO(pquerna): pointers. oops.
		return "if mj." + sf.Name + " != nil {" + "\n"

	default:
		// TODO(pquerna): fix types
		return "if true {" + "\n"
	}
}

func getGetInnerValue(ic *Inception, name string, typ reflect.Type) string {
	var out = ""
	if typ.Implements(marshalerBufType) || typeInInception(ic, typ) {
		out += "err = " + name + ".MarshalJSONBuf(buf)" + "\n"
		out += "if err != nil {" + "\n"
		out += "  return err" + "\n"
		out += "}" + "\n"
		return out
	}

	if typ.Implements(marshalerType) {
		out += "obj, err = " + name + ".MarshalJSON()" + "\n"
		out += "if err != nil {" + "\n"
		out += "  return err" + "\n"
		out += "}" + "\n"
		out += "buf.Write(obj)" + "\n"
		return out
	}

	switch typ.Kind() {
	case reflect.Int,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64:
		ic.OutputPills[pills.Pill_FormatBits] = true
		out += "ffjson_FormatBits(buf, uint64(" + name + "), 10, " + name + " < 0)" + "\n"
	case reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64,
		reflect.Uintptr:
		ic.OutputPills[pills.Pill_FormatBits] = true
		out += "ffjson_FormatBits(buf, uint64(" + name + "), 10, false)" + "\n"
	case reflect.Float32,
		reflect.Float64:
		ic.OutputImports[`"strconv"`] = true
		out += "buf.Write(strconv.AppendFloat([]byte{}, float64(" + name + "), 10))" + "\n"
	case reflect.Array,
		reflect.Slice:
		out += "if " + name + "!= nil {" + "\n"
		out += "buf.WriteString(`[`)" + "\n"
		out += "for _, v := range " + name + "{" + "\n"
		out += getGetInnerValue(ic, "v", typ.Elem())
		out += "}" + "\n"
		out += "buf.WriteString(`]`)" + "\n"
		out += "} else {" + "\n"
		out += "buf.WriteString(`null`)" + "\n"
		out += "}" + "\n"
	case reflect.String:
		ic.OutputPills[pills.Pill_WriteJsonString] = true
		out += "ffjson_WriteJsonString(buf, " + name + ")" + "\n"
	case reflect.Ptr:
		out += "if " + name + "!= nil {" + "\n"
		out += getGetInnerValue(ic, "v", typ.Elem())
		out += "}" + "\n"
		out += "buf.WriteString(`]`)" + "\n"
		out += "} else {" + "\n"
		out += "buf.WriteString(`null`)" + "\n"
		out += "}" + "\n"
	case reflect.Bool:
		out += "if " + name + " {" + "\n"
		out += "buf.WriteString(`true`)" + "\n"
		out += "} else {" + "\n"
		out += "buf.WriteString(`false`)" + "\n"
		out += "}" + "\n"
	default:
		ic.OutputImports[`"encoding/json"`] = true
		out += fmt.Sprintf("/* Falling back. type=%v kind=%v */\n", typ, typ.Kind())
		out += "obj, err = json.Marshal(" + name + ")" + "\n"
		out += "if err != nil {" + "\n"
		out += "  return err" + "\n"
		out += "}" + "\n"
		out += "buf.Write(obj)" + "\n"
	}
	return out
}

func getValue(ic *Inception, sf *StructField) string {
	return getGetInnerValue(ic, "mj."+sf.Name, sf.Typ)
}

func CreateMarshalJSON(ic *Inception, si *StructInfo) error {
	var out = ""

	ic.OutputImports[`"bytes"`] = true

	out += `func (mj *` + si.Name + `) MarshalJSON() ([]byte, error) {` + "\n"
	out += `var buf bytes.Buffer` + "\n"
	out += "buf.Grow(1024)" + "\n" // TOOD(pquerna): automatically calc a good size!
	out += `err := mj.MarshalJSONBuf(&buf)` + "\n"
	out += `if err != nil {` + "\n"
	out += "  return nil, err" + "\n"
	out += `}` + "\n"
	out += `return buf.Bytes(), nil` + "\n"
	out += `}` + "\n"

	out += `func (mj *` + si.Name + `) MarshalJSONBuf(buf *bytes.Buffer) (error) {` + "\n"
	out += `var err error` + "\n"
	out += `var obj []byte` + "\n"
	out += `var first bool = true` + "\n"
	out += `_ = obj` + "\n"
	out += `_ = err` + "\n"
	out += `_ = first` + "\n"
	out += "buf.WriteString(`{`)" + "\n"

	for _, f := range si.Fields {
		if f.JsonName == "-" {
			continue
		}

		if f.OmitEmpty {
			out += getOmitEmpty(ic, f)
		}

		out += "if first == true {" + "\n"
		out += "first = false" + "\n"
		out += "} else {" + "\n"
		out += "buf.WriteString(`,`)" + "\n"
		out += "}" + "\n"

		// JsonName is already escaped and quoted.
		out += "buf.WriteString(`" + f.JsonName + "`)" + "\n"
		out += "buf.WriteString(`:`)" + "\n"
		out += getValue(ic, f)
		if f.OmitEmpty {
			out += "}" + "\n"
		}
	}

	out += "buf.WriteString(`}`)" + "\n"
	out += `return nil` + "\n"
	out += `}` + "\n"
	ic.OutputFuncs = append(ic.OutputFuncs, out)
	return nil
}
<commit_msg>combine a WriteString<commit_after>/**
 *  Copyright 2014 Paul Querna
 *
 *  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 ffjsoninception

import (
	"fmt"
	"github.com/pquerna/ffjson/pills"
	"reflect"
)

func typeInInception(ic *Inception, typ reflect.Type) bool {
	for _, v := range ic.objs {
		if v.Typ == typ {
			return true
		}
	}

	return false
}

func getOmitEmpty(ic *Inception, sf *StructField) string {
	switch sf.Typ.Kind() {

	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return "if len(mj." + sf.Name + ") != 0 {" + "\n"

	case reflect.Int,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64,
		reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64,
		reflect.Uintptr,
		reflect.Float32,
		reflect.Float64:
		return "if mj." + sf.Name + " != 0 {" + "\n"

	case reflect.Bool:
		return "if mj." + sf.Name + " != false {" + "\n"

	case reflect.Interface, reflect.Ptr:
		// TODO(pquerna): pointers. oops.
		return "if mj." + sf.Name + " != nil {" + "\n"

	default:
		// TODO(pquerna): fix types
		return "if true {" + "\n"
	}
}

func getGetInnerValue(ic *Inception, name string, typ reflect.Type) string {
	var out = ""
	if typ.Implements(marshalerBufType) || typeInInception(ic, typ) {
		out += "err = " + name + ".MarshalJSONBuf(buf)" + "\n"
		out += "if err != nil {" + "\n"
		out += "  return err" + "\n"
		out += "}" + "\n"
		return out
	}

	if typ.Implements(marshalerType) {
		out += "obj, err = " + name + ".MarshalJSON()" + "\n"
		out += "if err != nil {" + "\n"
		out += "  return err" + "\n"
		out += "}" + "\n"
		out += "buf.Write(obj)" + "\n"
		return out
	}

	switch typ.Kind() {
	case reflect.Int,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64:
		ic.OutputPills[pills.Pill_FormatBits] = true
		out += "ffjson_FormatBits(buf, uint64(" + name + "), 10, " + name + " < 0)" + "\n"
	case reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64,
		reflect.Uintptr:
		ic.OutputPills[pills.Pill_FormatBits] = true
		out += "ffjson_FormatBits(buf, uint64(" + name + "), 10, false)" + "\n"
	case reflect.Float32,
		reflect.Float64:
		ic.OutputImports[`"strconv"`] = true
		out += "buf.Write(strconv.AppendFloat([]byte{}, float64(" + name + "), 10))" + "\n"
	case reflect.Array,
		reflect.Slice:
		out += "if " + name + "!= nil {" + "\n"
		out += "buf.WriteString(`[`)" + "\n"
		out += "for _, v := range " + name + "{" + "\n"
		out += getGetInnerValue(ic, "v", typ.Elem())
		out += "}" + "\n"
		out += "buf.WriteString(`]`)" + "\n"
		out += "} else {" + "\n"
		out += "buf.WriteString(`null`)" + "\n"
		out += "}" + "\n"
	case reflect.String:
		ic.OutputPills[pills.Pill_WriteJsonString] = true
		out += "ffjson_WriteJsonString(buf, " + name + ")" + "\n"
	case reflect.Ptr:
		out += "if " + name + "!= nil {" + "\n"
		out += getGetInnerValue(ic, "v", typ.Elem())
		out += "}" + "\n"
		out += "buf.WriteString(`]`)" + "\n"
		out += "} else {" + "\n"
		out += "buf.WriteString(`null`)" + "\n"
		out += "}" + "\n"
	case reflect.Bool:
		out += "if " + name + " {" + "\n"
		out += "buf.WriteString(`true`)" + "\n"
		out += "} else {" + "\n"
		out += "buf.WriteString(`false`)" + "\n"
		out += "}" + "\n"
	default:
		ic.OutputImports[`"encoding/json"`] = true
		out += fmt.Sprintf("/* Falling back. type=%v kind=%v */\n", typ, typ.Kind())
		out += "obj, err = json.Marshal(" + name + ")" + "\n"
		out += "if err != nil {" + "\n"
		out += "  return err" + "\n"
		out += "}" + "\n"
		out += "buf.Write(obj)" + "\n"
	}
	return out
}

func getValue(ic *Inception, sf *StructField) string {
	return getGetInnerValue(ic, "mj."+sf.Name, sf.Typ)
}

func CreateMarshalJSON(ic *Inception, si *StructInfo) error {
	var out = ""

	ic.OutputImports[`"bytes"`] = true

	out += `func (mj *` + si.Name + `) MarshalJSON() ([]byte, error) {` + "\n"
	out += `var buf bytes.Buffer` + "\n"
	out += "buf.Grow(1024)" + "\n" // TOOD(pquerna): automatically calc a good size!
	out += `err := mj.MarshalJSONBuf(&buf)` + "\n"
	out += `if err != nil {` + "\n"
	out += "  return nil, err" + "\n"
	out += `}` + "\n"
	out += `return buf.Bytes(), nil` + "\n"
	out += `}` + "\n"

	out += `func (mj *` + si.Name + `) MarshalJSONBuf(buf *bytes.Buffer) (error) {` + "\n"
	out += `var err error` + "\n"
	out += `var obj []byte` + "\n"
	out += `var first bool = true` + "\n"
	out += `_ = obj` + "\n"
	out += `_ = err` + "\n"
	out += `_ = first` + "\n"
	out += "buf.WriteString(`{`)" + "\n"

	for _, f := range si.Fields {
		if f.JsonName == "-" {
			continue
		}

		if f.OmitEmpty {
			out += getOmitEmpty(ic, f)
		}

		out += "if first == true {" + "\n"
		out += "first = false" + "\n"
		out += "} else {" + "\n"
		out += "buf.WriteString(`,`)" + "\n"
		out += "}" + "\n"

		// JsonName is already escaped and quoted.
		out += "buf.WriteString(`" + f.JsonName + ":`)" + "\n"
		out += getValue(ic, f)
		if f.OmitEmpty {
			out += "}" + "\n"
		}
	}

	out += "buf.WriteString(`}`)" + "\n"
	out += `return nil` + "\n"
	out += `}` + "\n"
	ic.OutputFuncs = append(ic.OutputFuncs, out)
	return nil
}
<|endoftext|>


<commit_before>package server

import (
	"io"
	"io/ioutil"
	"os"

	"emperror.dev/errors"
	"github.com/apex/log"
	"github.com/pterodactyl/wings/api"
	"github.com/pterodactyl/wings/server/backup"
)

// Notifies the panel of a backup's state and returns an error if one is encountered
// while performing this action.
func (s *Server) notifyPanelOfBackup(uuid string, ad *backup.ArchiveDetails, successful bool) error {
	if err := api.New().SendBackupStatus(uuid, ad.ToRequest(successful)); err != nil {
		if !api.IsRequestError(err) {
			s.Log().WithFields(log.Fields{
				"backup": uuid,
				"error":  err,
			}).Error("failed to notify panel of backup status due to wings error")

			return err
		}

		return errors.New(err.Error())
	}

	return nil
}

// Get all of the ignored files for a server based on its .pteroignore file in the root.
func (s *Server) getServerwideIgnoredFiles() (string, error) {
	f, st, err := s.Filesystem().File(".pteroignore")
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			return "", nil
		}
		return "", err
	}
	defer f.Close()
	if st.Mode()&os.ModeSymlink != 0 || st.Size() > 32*1024 {
		// Don't read a symlinked ignore file, or a file larger than 32KiB in size.
		return "", nil
	}
	b, err := ioutil.ReadAll(f)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

// Backup performs a server backup and then emits the event over the server
// websocket. We let the actual backup system handle notifying the panel of the
// status, but that won't emit a websocket event.
func (s *Server) Backup(b backup.BackupInterface) error {
	ignored := b.Ignored()
	if b.Ignored() == "" {
		if i, err := s.getServerwideIgnoredFiles(); err != nil {
			log.WithField("server", s.Id()).WithField("error", err).Warn("failed to get server-wide ignored files")
		} else {
			ignored = i
		}
	}

	ad, err := b.Generate(s.Filesystem().Path(), ignored)
	if err != nil {
		if err := s.notifyPanelOfBackup(b.Identifier(), &backup.ArchiveDetails{}, false); err != nil {
			s.Log().WithFields(log.Fields{
				"backup": b.Identifier(),
				"error":  err,
			}).Warn("failed to notify panel of failed backup state")
		} else {
			s.Log().WithField("backup", b.Identifier()).Info("notified panel of failed backup state")
		}

		_ = s.Events().PublishJson(BackupCompletedEvent+":"+b.Identifier(), map[string]interface{}{
			"uuid":          b.Identifier(),
			"is_successful": false,
			"checksum":      "",
			"checksum_type": "sha1",
			"file_size":     0,
		})

		return errors.WrapIf(err, "backup: error while generating server backup")
	}

	// Try to notify the panel about the status of this backup. If for some reason this request
	// fails, delete the archive from the daemon and return that error up the chain to the caller.
	if notifyError := s.notifyPanelOfBackup(b.Identifier(), ad, true); notifyError != nil {
		_ = b.Remove()

		s.Log().WithField("error", notifyError).Info("failed to notify panel of successful backup state")
		return err
	} else {
		s.Log().WithField("backup", b.Identifier()).Info("notified panel of successful backup state")
	}

	// Emit an event over the socket so we can update the backup in realtime on
	// the frontend for the server.
	_ = s.Events().PublishJson(BackupCompletedEvent+":"+b.Identifier(), map[string]interface{}{
		"uuid":          b.Identifier(),
		"is_successful": true,
		"checksum":      ad.Checksum,
		"checksum_type": "sha1",
		"file_size":     ad.Size,
	})

	return nil
}

// RestoreBackup calls the Restore function on the provided backup. Once this
// restoration is completed an event is emitted to the websocket to notify the
// Panel that is has been completed.
//
// In addition to the websocket event an API call is triggered to notify the
// Panel of the new state.
func (s *Server) RestoreBackup(b backup.BackupInterface, reader io.ReadCloser) (err error) {
	s.Config().SetSuspended(true)
	// Local backups will not pass a reader through to this function, so check first
	// to make sure it is a valid reader before trying to close it.
	defer func() {
		s.Config().SetSuspended(false)
		if reader != nil {
			reader.Close()
		}
	}()
	// Don't try to restore the server until we have completely stopped the running
	// instance, otherwise you'll likely hit all types of write errors due to the
	// server being suspended.
	err = s.Environment.WaitForStop(120, false)
	if err != nil {
		return err
	}
	// Send an API call to the Panel as soon as this function is done running so that
	// the Panel is informed of the restoration status of this backup.
	defer func() {
		if err := api.New().SendRestorationStatus(b.Identifier(), err == nil); err != nil {
			s.Log().WithField("error", err).WithField("backup", b.Identifier()).Error("failed to notify Panel of backup restoration status")
		}
	}()

	// Attempt to restore the backup to the server by running through each entry
	// in the file one at a time and writing them to the disk.
	err = b.Restore(reader, func(file string, r io.Reader) error {
		return s.Filesystem().Writefile(file, r)
	})

	return err
}
<commit_msg>Include a better stack here<commit_after>package server

import (
	"io"
	"io/ioutil"
	"os"

	"emperror.dev/errors"
	"github.com/apex/log"
	"github.com/pterodactyl/wings/api"
	"github.com/pterodactyl/wings/server/backup"
)

// Notifies the panel of a backup's state and returns an error if one is encountered
// while performing this action.
func (s *Server) notifyPanelOfBackup(uuid string, ad *backup.ArchiveDetails, successful bool) error {
	if err := api.New().SendBackupStatus(uuid, ad.ToRequest(successful)); err != nil {
		if !api.IsRequestError(err) {
			s.Log().WithFields(log.Fields{
				"backup": uuid,
				"error":  err,
			}).Error("failed to notify panel of backup status due to wings error")

			return err
		}

		return errors.New(err.Error())
	}

	return nil
}

// Get all of the ignored files for a server based on its .pteroignore file in the root.
func (s *Server) getServerwideIgnoredFiles() (string, error) {
	f, st, err := s.Filesystem().File(".pteroignore")
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			return "", nil
		}
		return "", err
	}
	defer f.Close()
	if st.Mode()&os.ModeSymlink != 0 || st.Size() > 32*1024 {
		// Don't read a symlinked ignore file, or a file larger than 32KiB in size.
		return "", nil
	}
	b, err := ioutil.ReadAll(f)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

// Backup performs a server backup and then emits the event over the server
// websocket. We let the actual backup system handle notifying the panel of the
// status, but that won't emit a websocket event.
func (s *Server) Backup(b backup.BackupInterface) error {
	ignored := b.Ignored()
	if b.Ignored() == "" {
		if i, err := s.getServerwideIgnoredFiles(); err != nil {
			log.WithField("server", s.Id()).WithField("error", err).Warn("failed to get server-wide ignored files")
		} else {
			ignored = i
		}
	}

	ad, err := b.Generate(s.Filesystem().Path(), ignored)
	if err != nil {
		if err := s.notifyPanelOfBackup(b.Identifier(), &backup.ArchiveDetails{}, false); err != nil {
			s.Log().WithFields(log.Fields{
				"backup": b.Identifier(),
				"error":  err,
			}).Warn("failed to notify panel of failed backup state")
		} else {
			s.Log().WithField("backup", b.Identifier()).Info("notified panel of failed backup state")
		}

		_ = s.Events().PublishJson(BackupCompletedEvent+":"+b.Identifier(), map[string]interface{}{
			"uuid":          b.Identifier(),
			"is_successful": false,
			"checksum":      "",
			"checksum_type": "sha1",
			"file_size":     0,
		})

		return errors.WrapIf(err, "backup: error while generating server backup")
	}

	// Try to notify the panel about the status of this backup. If for some reason this request
	// fails, delete the archive from the daemon and return that error up the chain to the caller.
	if notifyError := s.notifyPanelOfBackup(b.Identifier(), ad, true); notifyError != nil {
		_ = b.Remove()

		s.Log().WithField("error", notifyError).Info("failed to notify panel of successful backup state")
		return err
	} else {
		s.Log().WithField("backup", b.Identifier()).Info("notified panel of successful backup state")
	}

	// Emit an event over the socket so we can update the backup in realtime on
	// the frontend for the server.
	_ = s.Events().PublishJson(BackupCompletedEvent+":"+b.Identifier(), map[string]interface{}{
		"uuid":          b.Identifier(),
		"is_successful": true,
		"checksum":      ad.Checksum,
		"checksum_type": "sha1",
		"file_size":     ad.Size,
	})

	return nil
}

// RestoreBackup calls the Restore function on the provided backup. Once this
// restoration is completed an event is emitted to the websocket to notify the
// Panel that is has been completed.
//
// In addition to the websocket event an API call is triggered to notify the
// Panel of the new state.
func (s *Server) RestoreBackup(b backup.BackupInterface, reader io.ReadCloser) (err error) {
	s.Config().SetSuspended(true)
	// Local backups will not pass a reader through to this function, so check first
	// to make sure it is a valid reader before trying to close it.
	defer func() {
		s.Config().SetSuspended(false)
		if reader != nil {
			reader.Close()
		}
	}()
	// Don't try to restore the server until we have completely stopped the running
	// instance, otherwise you'll likely hit all types of write errors due to the
	// server being suspended.
	err = s.Environment.WaitForStop(120, false)
	if err != nil {
		return errors.WithStackIf(err)
	}
	// Send an API call to the Panel as soon as this function is done running so that
	// the Panel is informed of the restoration status of this backup.
	defer func() {
		if err := api.New().SendRestorationStatus(b.Identifier(), err == nil); err != nil {
			s.Log().WithField("error", err).WithField("backup", b.Identifier()).Error("failed to notify Panel of backup restoration status")
		}
	}()

	// Attempt to restore the backup to the server by running through each entry
	// in the file one at a time and writing them to the disk.
	err = b.Restore(reader, func(file string, r io.Reader) error {
		return s.Filesystem().Writefile(file, r)
	})

	return errors.WithStackIf(err)
}
<|endoftext|>


<commit_before>package server

import (
	"net/http"
	"time"

	"github.com/influxdata/chronograf"
)

// Logger is middleware that logs the request
func Logger(logger chronograf.Logger, next http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		now := time.Now()
		logger.
			WithField("component", "server").
			WithField("remote_addr", r.RemoteAddr).
			WithField("method", r.Method).
			WithField("url", r.URL).
			Info("Request")
		next.ServeHTTP(w, r)
		later := time.Now()
		elapsed := later.Sub(now)

		logger.
			WithField("component", "server").
			WithField("remote_addr", r.RemoteAddr).
			WithField("response_time", elapsed.String()).
			Info("Success")
	}
	return http.HandlerFunc(fn)
}
<commit_msg>Add HTTP status code to logs<commit_after>package server

import (
	"net/http"
	"time"

	"github.com/influxdata/chronograf"
)

type logResponseWriter struct {
	http.ResponseWriter

	responseCode int
}

func (l *logResponseWriter) WriteHeader(status int) {
	l.responseCode = status
	l.ResponseWriter.WriteHeader(status)
}

// Logger is middleware that logs the request
func Logger(logger chronograf.Logger, next http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		now := time.Now()
		logger.
			WithField("component", "server").
			WithField("remote_addr", r.RemoteAddr).
			WithField("method", r.Method).
			WithField("url", r.URL).
			Info("Request")

		lrr := &logResponseWriter{w, 0}
		next.ServeHTTP(lrr, r)
		later := time.Now()
		elapsed := later.Sub(now)

		logger.
			WithField("component", "server").
			WithField("remote_addr", r.RemoteAddr).
			WithField("response_time", elapsed.String()).
			WithField("code", lrr.responseCode).
			Info("Response: ", http.StatusText(lrr.responseCode))
	}
	return http.HandlerFunc(fn)
}
<|endoftext|>


<commit_before>package server

import (
	"net/http"

	"github.com/gorilla/mux"
)

func (s *Server) NewRouter() *mux.Router {
	type Route struct {
		Name        string
		Pattern     string
		Method      string
		HandlerFunc http.HandlerFunc
	}

	routes := []Route{
		Route{
			"UpdateSocket",
			"/updates",
			"GET",
			s.UpdateSocketHandler,
		},
		Route{
			"GroupIndex",
			"/groups",
			"GET",
			s.GroupIndexHandler,
		},
		Route{
			"Group",
			"/groups/{id}",
			"GET",
			s.GroupHandler,
		},
		Route{
			"GroupCreate",
			"/groups",
			"POST",
			s.GroupCreateHandler,
		},
		Route{
			"GroupExport",
			"/groups/{id}/export",
			"GET",
			s.GroupExportHandler,
		},
		Route{
			"GroupImport",
			"/groups/{id}/import",
			"POST",
			s.GroupImportHandler,
		},
		Route{
			"GroupModifyLabel",
			"/groups/{id}/label",
			"PUT",
			s.GroupModifyLabelHandler,
		},
		Route{
			"GroupModifyAllChildren",
			"/groups/{id}/children",
			"PUT",
			s.GroupModifyAllChildrenHandler,
		},
		Route{
			"GroupModifyChild",
			"/groups/{id}/children/{node_id}",
			"PUT",
			s.GroupModifyChildHandler,
		},
		Route{
			"GroupPosition",
			"/groups/{id}/position",
			"PUT",
			s.GroupPositionHandler,
		},
		Route{
			"GroupDelete",
			"/groups/{id}",
			"DELETE",
			s.GroupDeleteHandler,
		},
		Route{
			"BlockIndex",
			"/blocks",
			"GET",
			s.BlockIndexHandler,
		},
		Route{
			"Block",
			"/blocks/{id}",
			"GET",
			s.BlockHandler,
		},
		Route{
			"BlockCreate",
			"/blocks",
			"POST",
			s.BlockCreateHandler,
		},
		Route{
			"BlockDelete",
			"/blocks/{id}",
			"DELETE",
			s.BlockDeleteHandler,
		},
		Route{
			"BlockModifyName",
			"/blocks/{id}/label",
			"PUT",
			s.BlockModifyNameHandler,
		},
		Route{
			"BlockModifyRoute",
			"/blocks/{id}/routes/{index}",
			"PUT",
			s.BlockModifyRouteHandler,
		},
		Route{
			"BlockModifyPosition",
			"/blocks/{id}/position",
			"PUT",
			s.BlockModifyPositionHandler,
		},
		Route{
			"ConnectionIndex",
			"/connections",
			"GET",
			s.ConnectionIndexHandler,
		},
		Route{
			"ConnectionCreate",
			"/connections",
			"POST",
			s.ConnectionCreateHandler,
		},
		Route{
			"ConnectionModifyCoordinates",
			"/connections/{id}/coordinates",
			"PUT",
			s.ConnectionModifyCoordinates,
		},
		Route{
			"ConnectionDelete",
			"/connections/{id}",
			"DELETE",
			s.ConnectionDeleteHandler,
		},
		Route{
			"SourceCreate",
			"/sources",
			"POST",
			s.SourceCreateHandler,
		},
		Route{
			"SourceIndex",
			"/sources",
			"GET",
			s.SourceIndexHandler,
		},
		Route{
			"SourceModify",
			"/sources/{id}",
			"PUT",
			s.SourceModifyHandler,
		},
		Route{
			"Source",
			"/sources/{id}",
			"GET",
			s.SourceHandler,
		},
		Route{
			"Source",
			"/sources/{id}",
			"DELETE",
			s.SourceDeleteHandler,
		},
		Route{
			"Library",
			"/library",
			"GET",
			s.LibraryHandler,
		},
		Route{
			"LinkIndex",
			"/links",
			"GET",
			s.LinkIndexHandler,
		},
		Route{
			"LinkCreate",
			"/links",
			"POST",
			s.LinkCreateHandler,
		},
		Route{
			"LinkDelete",
			"/connections/{id}",
			"DELETE",
			s.ConnectionDeleteHandler,
		},
	}
	router := mux.NewRouter().StrictSlash(true)
	for _, route := range routes {
		var handler http.Handler

		handler = route.HandlerFunc
		handler = Logger(handler, route.Name)

		router.
			Methods(route.Method).
			Path(route.Pattern).
			Name(route.Name).
			Handler(handler)
	}

	router.PathPrefix("/").Handler(http.FileServer(http.Dir("./static/")))

	return router

}
<commit_msg>updating library endpoints<commit_after>package server

import (
	"net/http"

	"github.com/gorilla/mux"
)

func (s *Server) NewRouter() *mux.Router {
	type Route struct {
		Name        string
		Pattern     string
		Method      string
		HandlerFunc http.HandlerFunc
	}

	routes := []Route{
		Route{
			"UpdateSocket",
			"/updates",
			"GET",
			s.UpdateSocketHandler,
		},
		Route{
			"BlockLibrary",
			"/blocks/library",
			"GET",
			s.BlockLibraryHandler,
		},
		Route{
			"SourceLibrary",
			"/sources/library",
			"GET",
			s.SourceLibraryHandler,
		},
		Route{
			"GroupIndex",
			"/groups",
			"GET",
			s.GroupIndexHandler,
		},
		Route{
			"Group",
			"/groups/{id}",
			"GET",
			s.GroupHandler,
		},
		Route{
			"GroupCreate",
			"/groups",
			"POST",
			s.GroupCreateHandler,
		},
		Route{
			"GroupExport",
			"/groups/{id}/export",
			"GET",
			s.GroupExportHandler,
		},
		Route{
			"GroupImport",
			"/groups/{id}/import",
			"POST",
			s.GroupImportHandler,
		},
		Route{
			"GroupModifyLabel",
			"/groups/{id}/label",
			"PUT",
			s.GroupModifyLabelHandler,
		},
		Route{
			"GroupModifyAllChildren",
			"/groups/{id}/children",
			"PUT",
			s.GroupModifyAllChildrenHandler,
		},
		Route{
			"GroupModifyChild",
			"/groups/{id}/children/{node_id}",
			"PUT",
			s.GroupModifyChildHandler,
		},
		Route{
			"GroupPosition",
			"/groups/{id}/position",
			"PUT",
			s.GroupPositionHandler,
		},
		Route{
			"GroupDelete",
			"/groups/{id}",
			"DELETE",
			s.GroupDeleteHandler,
		},
		Route{
			"BlockIndex",
			"/blocks",
			"GET",
			s.BlockIndexHandler,
		},
		Route{
			"Block",
			"/blocks/{id}",
			"GET",
			s.BlockHandler,
		},
		Route{
			"BlockCreate",
			"/blocks",
			"POST",
			s.BlockCreateHandler,
		},
		Route{
			"BlockDelete",
			"/blocks/{id}",
			"DELETE",
			s.BlockDeleteHandler,
		},
		Route{
			"BlockModifyName",
			"/blocks/{id}/label",
			"PUT",
			s.BlockModifyNameHandler,
		},
		Route{
			"BlockModifyRoute",
			"/blocks/{id}/routes/{index}",
			"PUT",
			s.BlockModifyRouteHandler,
		},
		Route{
			"BlockModifyPosition",
			"/blocks/{id}/position",
			"PUT",
			s.BlockModifyPositionHandler,
		},
		Route{
			"ConnectionIndex",
			"/connections",
			"GET",
			s.ConnectionIndexHandler,
		},
		Route{
			"ConnectionCreate",
			"/connections",
			"POST",
			s.ConnectionCreateHandler,
		},
		Route{
			"ConnectionModifyCoordinates",
			"/connections/{id}/coordinates",
			"PUT",
			s.ConnectionModifyCoordinates,
		},
		Route{
			"ConnectionDelete",
			"/connections/{id}",
			"DELETE",
			s.ConnectionDeleteHandler,
		},
		Route{
			"SourceCreate",
			"/sources",
			"POST",
			s.SourceCreateHandler,
		},
		Route{
			"SourceIndex",
			"/sources",
			"GET",
			s.SourceIndexHandler,
		},
		Route{
			"SourceModify",
			"/sources/{id}",
			"PUT",
			s.SourceModifyHandler,
		},
		Route{
			"Source",
			"/sources/{id}",
			"GET",
			s.SourceHandler,
		},
		Route{
			"Source",
			"/sources/{id}",
			"DELETE",
			s.SourceDeleteHandler,
		},
		Route{
			"LinkIndex",
			"/links",
			"GET",
			s.LinkIndexHandler,
		},
		Route{
			"LinkCreate",
			"/links",
			"POST",
			s.LinkCreateHandler,
		},
		Route{
			"LinkDelete",
			"/connections/{id}",
			"DELETE",
			s.ConnectionDeleteHandler,
		},
	}
	router := mux.NewRouter().StrictSlash(true)
	for _, route := range routes {
		var handler http.Handler

		handler = route.HandlerFunc
		handler = Logger(handler, route.Name)

		router.
			Methods(route.Method).
			Path(route.Pattern).
			Name(route.Name).
			Handler(handler)
	}

	router.PathPrefix("/").Handler(http.FileServer(http.Dir("./static/")))

	return router

}
<|endoftext|>


<commit_before>package server

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"
)

// Routez represents detail information on current routes
type Routez struct {
	NumRoutes int          `json:"num_routes"`
	Routes    []*RouteInfo `json:"routes"`
}

// RouteInfo has detailed information on a per connection basis.
type RouteInfo struct {
	Cid       uint64 `json:"cid"`
	URL       string `json:"url"`
	IP        string `json:"ip"`
	Port      int    `json:"port"`
	Solicited bool   `json:"solicited"`
	Subs      uint32 `json:"subscriptions"`
	Pending   int    `json:"pending_size"`
	InMsgs    int64  `json:"in_msgs"`
	OutMsgs   int64  `json:"out_msgs"`
	InBytes   int64  `json:"in_bytes"`
	OutBytes  int64  `json:"out_bytes"`
}

// HandleConnz process HTTP requests for connection information.
func (s *Server) HandleRoutez(w http.ResponseWriter, req *http.Request) {

	if req.Method == "GET" {
		r := Routez{Routes: []*RouteInfo{}}

		// Walk the list
		s.mu.Lock()
		for _, route := range s.routes {
			ri := &RouteInfo{
				Cid:       route.cid,
				Subs:      route.subs.Count(),
				URL:       route.route.url.String(),
				Solicited: route.route.didSolicit,
				InMsgs:    route.inMsgs,
				OutMsgs:   route.outMsgs,
				InBytes:   route.inBytes,
				OutBytes:  route.outBytes,
			}
			if ip, ok := route.nc.(*net.TCPConn); ok {
				addr := ip.RemoteAddr().(*net.TCPAddr)
				ri.Port = addr.Port
				ri.IP = addr.IP.String()
			}
			r.Routes = append(r.Routes, ri)
		}
		s.mu.Unlock()

		r.NumRoutes = len(r.Routes)
		b, err := json.MarshalIndent(r, "", "  ")
		if err != nil {
			Logf("Error marshalling response to /routez request: %v", err)
		}
		w.Write(b)
	} else if req.Method == "PUT" {
		body := make([]byte, 1024)
		req.Body.Read(body)
		routeURL, err := url.Parse(strings.Trim(string(body), "\x00"))
		if err != nil {
			w.WriteHeader(400)
			w.Write([]byte(fmt.Sprintf(`{"error": "could not parse URL: %v"}`, err)))
			return
		}

		s.connectToRoute(routeURL)
		w.Write([]byte(`{"status": "ok"}`))
	} else if req.Method == "DELETE" {
		body := make([]byte, 1024)
		req.Body.Read(body)
		url := strings.Trim(string(body), "\x00")

		for _, route := range s.routes {
			if route.route.url.String() == url {
				route.mu.Lock()
				route.route.didSolicit = false // don't reconnect
				route.mu.Unlock()
				route.closeConnection()
				w.WriteHeader(200)
				w.Write([]byte(`{"status": "ok"}`))
				return
			}
		}
		w.WriteHeader(404)
		w.Write([]byte(`{"error": "could not find matching route"}`))
	}
}
<commit_msg>Route URL can be nil if wasn't a solicited route<commit_after>package server

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"
)

// Routez represents detail information on current routes
type Routez struct {
	NumRoutes int          `json:"num_routes"`
	Routes    []*RouteInfo `json:"routes"`
}

// RouteInfo has detailed information on a per connection basis.
type RouteInfo struct {
	Cid       uint64 `json:"cid"`
	URL       string `json:"url"`
	IP        string `json:"ip"`
	Port      int    `json:"port"`
	Solicited bool   `json:"solicited"`
	Subs      uint32 `json:"subscriptions"`
	Pending   int    `json:"pending_size"`
	InMsgs    int64  `json:"in_msgs"`
	OutMsgs   int64  `json:"out_msgs"`
	InBytes   int64  `json:"in_bytes"`
	OutBytes  int64  `json:"out_bytes"`
}

// HandleConnz process HTTP requests for connection information.
func (s *Server) HandleRoutez(w http.ResponseWriter, req *http.Request) {

	if req.Method == "GET" {
		r := Routez{Routes: []*RouteInfo{}}

		// Walk the list
		s.mu.Lock()
		for _, route := range s.routes {
			ri := &RouteInfo{
				Cid:       route.cid,
				Subs:      route.subs.Count(),
				Solicited: route.route.didSolicit,
				InMsgs:    route.inMsgs,
				OutMsgs:   route.outMsgs,
				InBytes:   route.inBytes,
				OutBytes:  route.outBytes,
			}

			if route.route.url != nil {
				ri.URL = route.route.url.String()
			}

			if ip, ok := route.nc.(*net.TCPConn); ok {
				addr := ip.RemoteAddr().(*net.TCPAddr)
				ri.Port = addr.Port
				ri.IP = addr.IP.String()
			}
			r.Routes = append(r.Routes, ri)
		}
		s.mu.Unlock()

		r.NumRoutes = len(r.Routes)
		b, err := json.MarshalIndent(r, "", "  ")
		if err != nil {
			Logf("Error marshalling response to /routez request: %v", err)
		}
		w.Write(b)
	} else if req.Method == "PUT" {
		body := make([]byte, 1024)
		req.Body.Read(body)
		routeURL, err := url.Parse(strings.Trim(string(body), "\x00"))
		if err != nil {
			w.WriteHeader(400)
			w.Write([]byte(fmt.Sprintf(`{"error": "could not parse URL: %v"}`, err)))
			return
		}

		s.connectToRoute(routeURL)
		w.Write([]byte(`{"status": "ok"}`))
	} else if req.Method == "DELETE" {
		body := make([]byte, 1024)
		req.Body.Read(body)
		url := strings.Trim(string(body), "\x00")

		s.mu.Lock()
		for _, route := range s.routes {
			if route.route.url.String() == url {
				route.mu.Lock()
				route.route.didSolicit = false // don't reconnect
				route.mu.Unlock()
				route.closeConnection()
				w.WriteHeader(200)
				w.Write([]byte(`{"status": "ok"}`))
				return
			}
		}
		s.mu.Unlock()
		w.WriteHeader(404)
		w.Write([]byte(`{"error": "could not find matching route"}`))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"github.com/golang/glog"
	"github.com/heidi-ann/hydra/cache"
	"github.com/heidi-ann/hydra/config"
	"github.com/heidi-ann/hydra/consensus"
	"github.com/heidi-ann/hydra/msgs"
	"github.com/heidi-ann/hydra/store"
	"io"
	"net"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"
)

var keyval *store.Store
var c *cache.Cache
var cons_io *msgs.Io

var notifyclient map[msgs.ClientRequest](chan msgs.ClientResponse)
var notifyclient_mutex sync.RWMutex

type Peer struct {
	id      int
	address string
	handled bool // TOOD: replace with Mutex
}

var peers []Peer
var peers_mutex sync.RWMutex

var client_port = flag.Int("client-port", 8080, "port to listen on for clients")
var peer_port = flag.Int("peer-port", 8090, "port to listen on for peers")
var id = flag.Int("id", -1, "server ID")
var config_file = flag.String("config", "example.conf", "Server configuration file")

func openFile(filename string) (*bufio.Writer, *bufio.Reader, bool) {
	// check if file exists already for logging
	var is_new bool
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		glog.Info("Creating and opening file: ", filename)
		is_new = true
	} else {
		glog.Info("Opening file: ", filename)
		is_new = false
	}

	// open file
	file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777)
	if err != nil {
		glog.Fatal(err)
	}

	// create writer and reader
	w := bufio.NewWriter(file)
	r := bufio.NewReader(file)
	return w, r, is_new
}

func stateMachine() {
	for {
		req := <-(*cons_io).OutgoingRequests
		glog.Info("Request has been safely replicated by consensus algorithm", req)

		// check if request already applied
		found, reply := c.Check(req)
		if found {
			glog.Info("Request found in cache and thus cannot be applied")
		} else {
			// apply request
			output := keyval.Process(req.Request)
			//keyval.Print()

			// write response to request cache
			reply = msgs.ClientResponse{
				req.ClientID, req.RequestID, output}
			c.Add(reply)
		}

		// if any handleRequests are waiting on this reply, then reply to them
		notifyclient_mutex.Lock()
		if notifyclient[req] != nil {
			notifyclient[req] <- reply
		}
		notifyclient_mutex.Unlock()
	}
}

func handleRequest(req msgs.ClientRequest) msgs.ClientResponse {
	glog.Info("Handling ", req.Request)

	// check if already applied
	found, res := c.Check(req)
	if found {
		glog.Info("Request found in cache")
		return res // FAST PASS
	}

	// CONSENESUS ALGORITHM HERE
	glog.Info("Passing request to consensus algorithm")
	(*cons_io).IncomingRequests <- req

	// wait for reply
	notifyclient_mutex.Lock()
	notifyclient[req] = make(chan msgs.ClientResponse)
	notifyclient_mutex.Unlock()
	reply := <-notifyclient[req]

	// check reply
	if reply.ClientID != req.ClientID {
		glog.Fatal("ClientID is different")
	}
	if reply.RequestID != req.RequestID {
		glog.Fatal("RequestID is different")
	}

	return reply
}

// iterative through peers and check there is a handler for each
// try to create one if not
func checkPeer() {
	for i := range peers {
		peers_mutex.RLock()
		failed := !peers[i].handled
		peers_mutex.RUnlock()
		if failed {
			glog.Info("Peer ", i, " is not currently connected")
			cn, err := net.Dial("tcp", peers[i].address)

			if err != nil {
				glog.Warning(err)
			} else {
				go handlePeer(cn, true)
			}
		} else {
			glog.Info("Peer ", i, " is currently connected")
		}
	}
}

func handlePeer(cn net.Conn, init bool) {
	addr := cn.RemoteAddr().String()
	if init {
		glog.Info("Outgoing peer connection to ", addr)
	} else {
		glog.Info("Incoming peer connection from ", addr)
	}

	defer glog.Warningf("Connection closed from %s ", addr)

	// handle requests
	reader := bufio.NewReader(cn)
	writer := bufio.NewWriter(cn)

	// exchange peer ID's
	_, _ = writer.WriteString(strconv.Itoa(*id) + "\n")
	_ = writer.Flush()
	text, _ := reader.ReadString('\n')
	glog.Info("Received ", text)
	peer_id, err := strconv.Atoi(strings.Trim(text, "\n"))
	if err != nil {
		glog.Warning(err)
		return
	}

	glog.Infof("Ready to handle traffic from peer %d at %s ", peer_id, addr)

	peers_mutex.Lock()
	peers[peer_id].handled = true
	peers_mutex.Unlock()

	close_err := make(chan error)
	go func() {
		for {
			// read request
			glog.Infof("Ready for next message from %d", peer_id)
			text, err := reader.ReadBytes(byte('\n'))
			if err != nil {
				glog.Warning(err)
				close_err <- err
				break
			}
			glog.Infof("Read from peer %d: ", peer_id, string(text))
			(*cons_io).Incoming.BytesToProtoMsg(text)

		}
	}()

	go func() {
		for {
			// send reply
			glog.Infof("Ready to send message to %d", peer_id)
			b, err := (*cons_io).OutgoingUnicast[peer_id].ProtoMsgToBytes()
			if err != nil {
				glog.Fatal("Could not marshal message")
			}
			glog.Infof("Sending to %d: %s", peer_id, string(b))
			_, err = writer.Write(b)
			_, err = writer.Write([]byte("\n"))
			if err != nil {
				glog.Warning(err)
				close_err <- err
				break
			}
			err = writer.Flush()
			glog.Info("Sent")
		}
	}()

	// block until connection fails
	<-close_err

	// tidy up
	glog.Warningf("No longer able to handle traffic from peer %d at %s ", peer_id, addr)
	peers_mutex.Unlock()
	peers[peer_id].handled = false
	peers_mutex.Lock()
	(*cons_io).Failure <- peer_id
	cn.Close()
}

func handleConnection(cn net.Conn) {
	glog.Info("Incoming client connection from ",
		cn.RemoteAddr().String())

	reader := bufio.NewReader(cn)
	writer := bufio.NewWriter(cn)

	for {

		// read request
		glog.Info("Reading")
		text, err := reader.ReadBytes(byte('\n'))
		if err != nil {
			if err == io.EOF {
				break
			}
			glog.Fatal(err)
		}
		glog.Info(string(text))
		req := new(msgs.ClientRequest)
		err = msgs.Unmarshal(text, req)
		if err != nil {
			glog.Fatal(err)
		}

		// construct reply
		reply := handleRequest(*req)
		b, err := msgs.Marshal(reply)
		if err != nil {
			glog.Fatal("error:", err)
		}
		glog.Info(string(b))

		// send reply
		// TODO: FIX currently all server send back replies
		glog.Info("Sending ", string(b))
		n, err := writer.Write(b)
		_, err = writer.Write([]byte("\n"))
		if err != nil {
			glog.Fatal(err)
		}

		// tidy up
		err = writer.Flush()
		glog.Info("Finished sending ", n, " bytes")

	}

	cn.Close()
}

func main() {
	// set up logging
	flag.Parse()
	defer glog.Flush()

	conf := config.ParseServerConfig(*config_file)
	if *id == -1 {
		glog.Fatal("ID is required")
	}

	glog.Info("Starting server ", *id)
	defer glog.Warning("Shutting down server ", *id)

	//set up state machine
	keyval = store.New()
	c = cache.Create()
	// setup IO
	cons_io = msgs.MakeIo(1000, len(conf.Peers.Address))

	notifyclient = make(map[msgs.ClientRequest](chan msgs.ClientResponse))
	notifyclient_mutex = sync.RWMutex{}
	go stateMachine()

	// setting up persistent log
	disk, disk_reader, is_empty := openFile("persistent_log_" + strconv.Itoa(*id) + ".temp")
	defer disk.Flush()
	meta_disk, meta_disk_reader, is_new := openFile("persistent_data_" + strconv.Itoa(*id) + ".temp")

	// check persistent storage for commands
	found := false
	log := make([]msgs.Entry, 1000) //TODO: Fix this

	if !is_empty {
		for {
			b, err := disk_reader.ReadBytes(byte('\n'))
			if err != nil {
				glog.Info("No more commands in persistent storage")
				break
			}
			found = true
			var update msgs.LogUpdate
			err = msgs.Unmarshal(b, &update)
			if err != nil {
				glog.Fatal("Cannot parse log update", err)
			}
			log[update.Index] = update.Entry
			glog.Info("Adding for persistent storage :", update)
		}
	}

	// check persistent storage for view
	view := 0
	if !is_new {
		for {
			b, err := meta_disk_reader.ReadBytes(byte('\n'))
			if err != nil {
				glog.Info("No more view updates in persistent storage")
				break
			}
			found = true
			view, _ = strconv.Atoi(string(b))
		}
	}

	// write updates to persistent storage
	go func() {
		for {
			// get write requests
			select {
			//disgard view updates
			case view := <-(*cons_io).ViewPersist:
				glog.Info("Updating view to ", view)
				_, err := meta_disk.Write([]byte(strconv.Itoa(view)))
				_, err = meta_disk.Write([]byte("\n"))
				_ = disk.Flush()
				if err != nil {
					glog.Fatal(err)
				}
			case log := <-(*cons_io).LogPersist:
				glog.Info("Updating log with ", log)
				b, err := msgs.Marshal(log)
				// write to persistent storage
				_, err = disk.Write(b)
				_, err = disk.Write([]byte("\n"))
				_ = disk.Flush()
				if err != nil {
					glog.Fatal(err)
				}
			}

		}
	}()

	// set up client server
	glog.Info("Starting up client server")
	listeningPort := ":" + strconv.Itoa(*client_port)
	ln, err := net.Listen("tcp", listeningPort)
	if err != nil {
		glog.Fatal(err)
	}

	// handle for incoming clients
	go func() {
		for {
			conn, err := ln.Accept()
			if err != nil {
				glog.Fatal(err)
			}
			go handleConnection(conn)
		}
	}()

	//set up peer state
	peers = make([]Peer, len(conf.Peers.Address))
	for i := range conf.Peers.Address {
		peers[i] = Peer{
			i, conf.Peers.Address[i], false}
	}
	peers_mutex = sync.RWMutex{}

	//set up peer server
	glog.Info("Starting up peer server")
	listeningPort = ":" + strconv.Itoa(*peer_port)
	lnPeers, err := net.Listen("tcp", listeningPort)
	if err != nil {
		glog.Fatal(err)
	}

	// handle local peer (without sending network traffic)
	peers_mutex.Lock()
	peers[*id].handled = true
	peers_mutex.Unlock()
	from := &((*cons_io).Incoming)
	go from.Forward((*cons_io).OutgoingUnicast[*id])

	// handle for incoming peers
	go func() {
		for {
			conn, err := lnPeers.Accept()
			if err != nil {
				glog.Fatal(err)
			}
			go handlePeer(conn, false)
		}
	}()

	// regularly check if all peers are connected and retry if not
	go func() {
		for {
			checkPeer()
			time.Sleep(100 * time.Millisecond)
		}
	}()

	// setting up the consensus algorithm
	cons_config := consensus.Config{*id, len(conf.Peers.Address)}
	if !found {
		glog.Info("Starting fresh consensus instance")
		go consensus.Init(cons_io, cons_config)
	} else {
		glog.Info("Restoring consensus instance")
		go consensus.Recover(cons_io, cons_config, view, log)
	}
	go cons_io.DumpPersistentStorage()

	// tidy up
	glog.Info("Setup complete")

	// waiting for exit
	// always flush (whatever happens)
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
	sig := <-sigs
	glog.Flush()
	glog.Warning("Shutting down due to ", sig)
}
<commit_msg>removing unnecessary struct derefs from server.go<commit_after>package main

import (
	"bufio"
	"flag"
	"github.com/golang/glog"
	"github.com/heidi-ann/hydra/cache"
	"github.com/heidi-ann/hydra/config"
	"github.com/heidi-ann/hydra/consensus"
	"github.com/heidi-ann/hydra/msgs"
	"github.com/heidi-ann/hydra/store"
	"io"
	"net"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"
)

var keyval *store.Store
var c *cache.Cache
var cons_io *msgs.Io

var notifyclient map[msgs.ClientRequest](chan msgs.ClientResponse)
var notifyclient_mutex sync.RWMutex

type Peer struct {
	id      int
	address string
	handled bool // TOOD: replace with Mutex
}

var peers []Peer
var peers_mutex sync.RWMutex

var client_port = flag.Int("client-port", 8080, "port to listen on for clients")
var peer_port = flag.Int("peer-port", 8090, "port to listen on for peers")
var id = flag.Int("id", -1, "server ID")
var config_file = flag.String("config", "example.conf", "Server configuration file")

func openFile(filename string) (*bufio.Writer, *bufio.Reader, bool) {
	// check if file exists already for logging
	var is_new bool
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		glog.Info("Creating and opening file: ", filename)
		is_new = true
	} else {
		glog.Info("Opening file: ", filename)
		is_new = false
	}

	// open file
	file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777)
	if err != nil {
		glog.Fatal(err)
	}

	// create writer and reader
	w := bufio.NewWriter(file)
	r := bufio.NewReader(file)
	return w, r, is_new
}

func stateMachine() {
	for {
		req := <-cons_io.OutgoingRequests
		glog.Info("Request has been safely replicated by consensus algorithm", req)

		// check if request already applied
		found, reply := c.Check(req)
		if found {
			glog.Info("Request found in cache and thus cannot be applied")
		} else {
			// apply request
			output := keyval.Process(req.Request)
			//keyval.Print()

			// write response to request cache
			reply = msgs.ClientResponse{
				req.ClientID, req.RequestID, output}
			c.Add(reply)
		}

		// if any handleRequests are waiting on this reply, then reply to them
		notifyclient_mutex.Lock()
		if notifyclient[req] != nil {
			notifyclient[req] <- reply
		}
		notifyclient_mutex.Unlock()
	}
}

func handleRequest(req msgs.ClientRequest) msgs.ClientResponse {
	glog.Info("Handling ", req.Request)

	// check if already applied
	found, res := c.Check(req)
	if found {
		glog.Info("Request found in cache")
		return res // FAST PASS
	}

	// CONSENESUS ALGORITHM HERE
	glog.Info("Passing request to consensus algorithm")
	cons_io.IncomingRequests <- req

	// wait for reply
	notifyclient_mutex.Lock()
	notifyclient[req] = make(chan msgs.ClientResponse)
	notifyclient_mutex.Unlock()
	reply := <-notifyclient[req]

	// check reply
	if reply.ClientID != req.ClientID {
		glog.Fatal("ClientID is different")
	}
	if reply.RequestID != req.RequestID {
		glog.Fatal("RequestID is different")
	}

	return reply
}

// iterative through peers and check there is a handler for each
// try to create one if not
func checkPeer() {
	for i := range peers {
		peers_mutex.RLock()
		failed := !peers[i].handled
		peers_mutex.RUnlock()
		if failed {
			glog.Info("Peer ", i, " is not currently connected")
			cn, err := net.Dial("tcp", peers[i].address)

			if err != nil {
				glog.Warning(err)
			} else {
				go handlePeer(cn, true)
			}
		} else {
			glog.Info("Peer ", i, " is currently connected")
		}
	}
}

func handlePeer(cn net.Conn, init bool) {
	addr := cn.RemoteAddr().String()
	if init {
		glog.Info("Outgoing peer connection to ", addr)
	} else {
		glog.Info("Incoming peer connection from ", addr)
	}

	defer glog.Warningf("Connection closed from %s ", addr)

	// handle requests
	reader := bufio.NewReader(cn)
	writer := bufio.NewWriter(cn)

	// exchange peer ID's
	_, _ = writer.WriteString(strconv.Itoa(*id) + "\n")
	_ = writer.Flush()
	text, _ := reader.ReadString('\n')
	glog.Info("Received ", text)
	peer_id, err := strconv.Atoi(strings.Trim(text, "\n"))
	if err != nil {
		glog.Warning(err)
		return
	}

	glog.Infof("Ready to handle traffic from peer %d at %s ", peer_id, addr)

	peers_mutex.Lock()
	peers[peer_id].handled = true
	peers_mutex.Unlock()

	close_err := make(chan error)
	go func() {
		for {
			// read request
			glog.Infof("Ready for next message from %d", peer_id)
			text, err := reader.ReadBytes(byte('\n'))
			if err != nil {
				glog.Warning(err)
				close_err <- err
				break
			}
			glog.Infof("Read from peer %d: ", peer_id, string(text))
			cons_io.Incoming.BytesToProtoMsg(text)

		}
	}()

	go func() {
		for {
			// send reply
			glog.Infof("Ready to send message to %d", peer_id)
			b, err := cons_io.OutgoingUnicast[peer_id].ProtoMsgToBytes()
			if err != nil {
				glog.Fatal("Could not marshal message")
			}
			glog.Infof("Sending to %d: %s", peer_id, string(b))
			_, err = writer.Write(b)
			_, err = writer.Write([]byte("\n"))
			if err != nil {
				glog.Warning(err)
				close_err <- err
				break
			}
			err = writer.Flush()
			glog.Info("Sent")
		}
	}()

	// block until connection fails
	<-close_err

	// tidy up
	glog.Warningf("No longer able to handle traffic from peer %d at %s ", peer_id, addr)
	peers_mutex.Unlock()
	peers[peer_id].handled = false
	peers_mutex.Lock()
	cons_io.Failure <- peer_id
	cn.Close()
}

func handleConnection(cn net.Conn) {
	glog.Info("Incoming client connection from ",
		cn.RemoteAddr().String())

	reader := bufio.NewReader(cn)
	writer := bufio.NewWriter(cn)

	for {

		// read request
		glog.Info("Reading")
		text, err := reader.ReadBytes(byte('\n'))
		if err != nil {
			if err == io.EOF {
				break
			}
			glog.Fatal(err)
		}
		glog.Info(string(text))
		req := new(msgs.ClientRequest)
		err = msgs.Unmarshal(text, req)
		if err != nil {
			glog.Fatal(err)
		}

		// construct reply
		reply := handleRequest(*req)
		b, err := msgs.Marshal(reply)
		if err != nil {
			glog.Fatal("error:", err)
		}
		glog.Info(string(b))

		// send reply
		// TODO: FIX currently all server send back replies
		glog.Info("Sending ", string(b))
		n, err := writer.Write(b)
		_, err = writer.Write([]byte("\n"))
		if err != nil {
			glog.Fatal(err)
		}

		// tidy up
		err = writer.Flush()
		glog.Info("Finished sending ", n, " bytes")

	}

	cn.Close()
}

func main() {
	// set up logging
	flag.Parse()
	defer glog.Flush()

	conf := config.ParseServerConfig(*config_file)
	if *id == -1 {
		glog.Fatal("ID is required")
	}

	glog.Info("Starting server ", *id)
	defer glog.Warning("Shutting down server ", *id)

	//set up state machine
	keyval = store.New()
	c = cache.Create()
	// setup IO
	cons_io = msgs.MakeIo(1000, len(conf.Peers.Address))

	notifyclient = make(map[msgs.ClientRequest](chan msgs.ClientResponse))
	notifyclient_mutex = sync.RWMutex{}
	go stateMachine()

	// setting up persistent log
	disk, disk_reader, is_empty := openFile("persistent_log_" + strconv.Itoa(*id) + ".temp")
	defer disk.Flush()
	meta_disk, meta_disk_reader, is_new := openFile("persistent_data_" + strconv.Itoa(*id) + ".temp")

	// check persistent storage for commands
	found := false
	log := make([]msgs.Entry, 1000) //TODO: Fix this

	if !is_empty {
		for {
			b, err := disk_reader.ReadBytes(byte('\n'))
			if err != nil {
				glog.Info("No more commands in persistent storage")
				break
			}
			found = true
			var update msgs.LogUpdate
			err = msgs.Unmarshal(b, &update)
			if err != nil {
				glog.Fatal("Cannot parse log update", err)
			}
			log[update.Index] = update.Entry
			glog.Info("Adding for persistent storage :", update)
		}
	}

	// check persistent storage for view
	view := 0
	if !is_new {
		for {
			b, err := meta_disk_reader.ReadBytes(byte('\n'))
			if err != nil {
				glog.Info("No more view updates in persistent storage")
				break
			}
			found = true
			view, _ = strconv.Atoi(string(b))
		}
	}

	// write updates to persistent storage
	go func() {
		for {
			// get write requests
			select {
			//disgard view updates
			case view := <-cons_io.ViewPersist:
				glog.Info("Updating view to ", view)
				_, err := meta_disk.Write([]byte(strconv.Itoa(view)))
				_, err = meta_disk.Write([]byte("\n"))
				_ = disk.Flush()
				if err != nil {
					glog.Fatal(err)
				}
			case log := <-cons_io.LogPersist:
				glog.Info("Updating log with ", log)
				b, err := msgs.Marshal(log)
				// write to persistent storage
				_, err = disk.Write(b)
				_, err = disk.Write([]byte("\n"))
				_ = disk.Flush()
				if err != nil {
					glog.Fatal(err)
				}
			}

		}
	}()

	// set up client server
	glog.Info("Starting up client server")
	listeningPort := ":" + strconv.Itoa(*client_port)
	ln, err := net.Listen("tcp", listeningPort)
	if err != nil {
		glog.Fatal(err)
	}

	// handle for incoming clients
	go func() {
		for {
			conn, err := ln.Accept()
			if err != nil {
				glog.Fatal(err)
			}
			go handleConnection(conn)
		}
	}()

	//set up peer state
	peers = make([]Peer, len(conf.Peers.Address))
	for i := range conf.Peers.Address {
		peers[i] = Peer{
			i, conf.Peers.Address[i], false}
	}
	peers_mutex = sync.RWMutex{}

	//set up peer server
	glog.Info("Starting up peer server")
	listeningPort = ":" + strconv.Itoa(*peer_port)
	lnPeers, err := net.Listen("tcp", listeningPort)
	if err != nil {
		glog.Fatal(err)
	}

	// handle local peer (without sending network traffic)
	peers_mutex.Lock()
	peers[*id].handled = true
	peers_mutex.Unlock()
	from := &(cons_io.Incoming)
	go from.Forward(cons_io.OutgoingUnicast[*id])

	// handle for incoming peers
	go func() {
		for {
			conn, err := lnPeers.Accept()
			if err != nil {
				glog.Fatal(err)
			}
			go handlePeer(conn, false)
		}
	}()

	// regularly check if all peers are connected and retry if not
	go func() {
		for {
			checkPeer()
			time.Sleep(100 * time.Millisecond)
		}
	}()

	// setting up the consensus algorithm
	cons_config := consensus.Config{*id, len(conf.Peers.Address)}
	if !found {
		glog.Info("Starting fresh consensus instance")
		go consensus.Init(cons_io, cons_config)
	} else {
		glog.Info("Restoring consensus instance")
		go consensus.Recover(cons_io, cons_config, view, log)
	}
	go cons_io.DumpPersistentStorage()

	// tidy up
	glog.Info("Setup complete")

	// waiting for exit
	// always flush (whatever happens)
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
	sig := <-sigs
	glog.Flush()
	glog.Warning("Shutting down due to ", sig)
}
<|endoftext|>