<commit_before>package config

import (
	"crypto/tls"

	"github.com/sensu/uchiwa/uchiwa/authentication"
	"github.com/sensu/uchiwa/uchiwa/structs"
)

// Config struct contains []SensuConfig and UchiwaConfig structs
type Config struct {
	Dashboard *GlobalConfig `json:",omitempty"`
	Sensu     []SensuConfig
	Uchiwa    GlobalConfig
}

// SensuConfig struct contains conf about a Sensu API
type SensuConfig struct {
	Name     string
	Host     string
	Port     int
	Ssl      bool
	Insecure bool
	URL      string
	User     string
	Path     string
	Pass     string
	Timeout  int
}

// GlobalConfig struct contains conf about Uchiwa
type GlobalConfig struct {
	Host         string
	Port         int
	LogLevel     string
	Refresh      int
	Pass         string
	User         string
	Users        []authentication.User
	Audit        Audit
	Auth         structs.Auth
	Db           Db
	Enterprise   bool
	Github       Github
	Gitlab       Gitlab
	Ldap         Ldap
	OIDC         OIDC
	SSL          SSL
	UsersOptions UsersOptions
}

// Audit struct contains the config of the Audit logger
type Audit struct {
	Level   string
	Logfile string
}

// Db struct contains the SQL driver configuration
type Db struct {
	Driver string
	Scheme string
}

// Github struct contains the GitHub driver configuration
type Github struct {
	ClientID     string
	ClientSecret string
	Roles        []authentication.Role
	Server       string
}

// Gitlab struct contains the Gitlab driver configuration
type Gitlab struct {
	ClientID     string `json:"applicationid"`
	ClientSecret string `json:"secret"`
	RedirectURL  string
	Roles        []authentication.Role
	Server       string
}

// Ldap struct contains the LDAP driver configuration
type Ldap struct {
	LdapServer
	Debug   bool
	Roles   []authentication.Role
	Servers []LdapServer
}

type LdapServer struct {
	Server               string
	Port                 int
	BaseDN               string
	BindUser             string
	BindPass             string
	Dialect              string
	DisableNestedGroups  bool
	GroupBaseDN          string
	GroupObjectClass     string
	GroupMemberAttribute string
	Insecure             bool
	Security             string
	TLSConfig            *tls.Config
	UserAttribute        string
	UserBaseDN           string
	UserObjectClass      string
}

// OIDC struct contains the OIDC driver configuration
type OIDC struct {
	ClientID     string
	ClientSecret string
	Insecure     bool
	Roles        []authentication.Role
	Server       string
}

// SSL struct contains the path the SSL certificate and key
type SSL struct {
	CertFile string
	KeyFile  string
}

// UsersOptions struct contains various config tweaks
type UsersOptions struct {
	DateFormat             string
	DefaultTheme           string
	DisableNoExpiration    bool
	Favicon                string
	LogoURL                string
	Refresh                int
	RequireSilencingReason bool
	SilenceDurations       []float32
}
<commit_msg>[Enteprise] Add support for RedirectURL OIDC configuration attribute<commit_after>package config

import (
	"crypto/tls"

	"github.com/sensu/uchiwa/uchiwa/authentication"
	"github.com/sensu/uchiwa/uchiwa/structs"
)

// Config struct contains []SensuConfig and UchiwaConfig structs
type Config struct {
	Dashboard *GlobalConfig `json:",omitempty"`
	Sensu     []SensuConfig
	Uchiwa    GlobalConfig
}

// SensuConfig struct contains conf about a Sensu API
type SensuConfig struct {
	Name     string
	Host     string
	Port     int
	Ssl      bool
	Insecure bool
	URL      string
	User     string
	Path     string
	Pass     string
	Timeout  int
}

// GlobalConfig struct contains conf about Uchiwa
type GlobalConfig struct {
	Host         string
	Port         int
	LogLevel     string
	Refresh      int
	Pass         string
	User         string
	Users        []authentication.User
	Audit        Audit
	Auth         structs.Auth
	Db           Db
	Enterprise   bool
	Github       Github
	Gitlab       Gitlab
	Ldap         Ldap
	OIDC         OIDC
	SSL          SSL
	UsersOptions UsersOptions
}

// Audit struct contains the config of the Audit logger
type Audit struct {
	Level   string
	Logfile string
}

// Db struct contains the SQL driver configuration
type Db struct {
	Driver string
	Scheme string
}

// Github struct contains the GitHub driver configuration
type Github struct {
	ClientID     string
	ClientSecret string
	Roles        []authentication.Role
	Server       string
}

// Gitlab struct contains the Gitlab driver configuration
type Gitlab struct {
	ClientID     string `json:"applicationid"`
	ClientSecret string `json:"secret"`
	RedirectURL  string
	Roles        []authentication.Role
	Server       string
}

// Ldap struct contains the LDAP driver configuration
type Ldap struct {
	LdapServer
	Debug   bool
	Roles   []authentication.Role
	Servers []LdapServer
}

type LdapServer struct {
	Server               string
	Port                 int
	BaseDN               string
	BindUser             string
	BindPass             string
	Dialect              string
	DisableNestedGroups  bool
	GroupBaseDN          string
	GroupObjectClass     string
	GroupMemberAttribute string
	Insecure             bool
	Security             string
	TLSConfig            *tls.Config
	UserAttribute        string
	UserBaseDN           string
	UserObjectClass      string
}

// OIDC struct contains the OIDC driver configuration
type OIDC struct {
	ClientID     string
	ClientSecret string
	Insecure     bool
	RedirectURL  string
	Roles        []authentication.Role
	Server       string
}

// SSL struct contains the path the SSL certificate and key
type SSL struct {
	CertFile string
	KeyFile  string
}

// UsersOptions struct contains various config tweaks
type UsersOptions struct {
	DateFormat             string
	DefaultTheme           string
	DisableNoExpiration    bool
	Favicon                string
	LogoURL                string
	Refresh                int
	RequireSilencingReason bool
	SilenceDurations       []float32
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"os/signal"
	"time"
)

func main() {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
	defer stop()

	ch := make(chan Number)

	go func() {
		err := runCounter(ctx, ch)
		if err != nil {
			log.Printf("counter: %v", err)
		}
	}()

	go func() {
		for v := range ch {
			println(v.Value)
		}
	}()

	select {
	case <-ctx.Done():
		fmt.Println(ctx.Err())
		stop()
	}
}

type Number struct {
	Value int
}

func runCounter(ctx context.Context, out chan<- Number) error {
	x := 0

	for {
		select {
		case <-ctx.Done():
			return fmt.Errorf("stoped at %v, err: %v", x, ctx.Err())
		default:
		}

		x++

		out <- Number{Value: x}

		time.Sleep(1e9)
	}

	return nil
}
<commit_msg>grace: clean main<commit_after>package main

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"time"
)

func main() {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
	defer stop()

	<-ctx.Done()

	fmt.Println("the end:", ctx.Err())
}

type Number struct {
	Value int
}

func runCounter(ctx context.Context, out chan<- Number) error {
	x := 0

	for {
		select {
		case <-ctx.Done():
			return fmt.Errorf("stoped at %v, err: %v", x, ctx.Err())
		default:
		}

		x++

		out <- Number{Value: x}

		time.Sleep(1e9)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"errors"
	"log"
	"os"
	"os/signal"
)

func main() {
	lgr := log.New(os.Stderr, "grace: ", 0)

	err := run()
	if err != nil {
		if errors.Is(err, context.Canceled) {
			return
		}

		lgr.Printf("%v", err)
		os.Exit(1)
	}

}

func run() error {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
	defer stop()

	<-ctx.Done()

	return ctx.Err()
}
<commit_msg>grace: clean err handle<commit_after>package main

import (
	"context"
	"errors"
	"log"
	"os"
	"os/signal"
)

func main() {
	lgr := log.New(os.Stderr, "grace: ", 0)

	err := run()
	if err != nil {
		lgr.Printf("%v", err)
		os.Exit(1)
	}

}

func run() error {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
	defer stop()

	<-ctx.Done()

	err := ctx.Err()
	if errors.Is(err, context.Canceled) {
		return nil
	}

	return err
}
<|endoftext|>


<commit_before>package gorums

import (
	gorumsproto "github.com/relab/gorums"

	"github.com/gogo/protobuf/proto"
	"github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
)

func hasQRPCExtension(method *descriptor.MethodDescriptorProto) bool {
	if method.Options == nil {
		return false
	}
	value, err := proto.GetExtension(method.Options, gorumsproto.E_Qrpc)
	if err != nil {
		return false
	}
	if value == nil {
		return false
	}
	if value.(*bool) == nil {
		return false
	}
	return true
}

func hasCorrectableExtension(method *descriptor.MethodDescriptorProto) bool {
	if method.Options == nil {
		return false
	}
	value, err := proto.GetExtension(method.Options, gorumsproto.E_Correctable)
	if err != nil {
		return false
	}
	if value == nil {
		return false
	}
	if value.(*bool) == nil {
		return false
	}
	return true
}

func hasMcastExtension(method *descriptor.MethodDescriptorProto) bool {
	if method.Options == nil {
		return false
	}
	value, err := proto.GetExtension(method.Options, gorumsproto.E_Multicast)
	if err != nil {
		return false
	}
	if value == nil {
		return false
	}
	if value.(*bool) == nil {
		return false
	}
	return true
}

func hasFutureExtension(method *descriptor.MethodDescriptorProto) bool {
	if method.Options == nil {
		return false
	}
	value, err := proto.GetExtension(method.Options, gorumsproto.E_Future)
	if err != nil {
		return false
	}
	if value == nil {
		return false
	}
	if value.(*bool) == nil {
		return false
	}
	return true
}
<commit_msg>plugings/gorums: reduce some duplication in ext.go<commit_after>package gorums

import (
	gorumsproto "github.com/relab/gorums"

	"github.com/gogo/protobuf/proto"
	"github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
)

func hasQRPCExtension(method *descriptor.MethodDescriptorProto) bool {
	if method.Options == nil {
		return false
	}
	value, err := proto.GetExtension(method.Options, gorumsproto.E_Qrpc)
	if err != nil {
		return false
	}
	return checkExtensionBoolValue(value)
}

func hasCorrectableExtension(method *descriptor.MethodDescriptorProto) bool {
	if method.Options == nil {
		return false
	}
	value, err := proto.GetExtension(method.Options, gorumsproto.E_Correctable)
	if err != nil {
		return false
	}
	return checkExtensionBoolValue(value)
}

func hasMcastExtension(method *descriptor.MethodDescriptorProto) bool {
	if method.Options == nil {
		return false
	}
	value, err := proto.GetExtension(method.Options, gorumsproto.E_Multicast)
	if err != nil {
		return false
	}
	return checkExtensionBoolValue(value)
}

func hasFutureExtension(method *descriptor.MethodDescriptorProto) bool {
	if method.Options == nil {
		return false
	}
	value, err := proto.GetExtension(method.Options, gorumsproto.E_Future)
	if err != nil {
		return false
	}
	return checkExtensionBoolValue(value)
}

func checkExtensionBoolValue(value interface{}) bool {
	if value == nil {
		return false
	}
	if value.(*bool) == nil {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package plugins

import (
    "time"
    "sync"
    "github.com/sn0w/discordgo"
    "git.lukas.moe/sn0w/Karen/logger"
    "git.lukas.moe/sn0w/Karen/helpers"
    "strings"
    "os/exec"
    "bufio"
    "encoding/binary"
    "io"
    "git.lukas.moe/sn0w/radio-b"
    "git.lukas.moe/sn0w/Karen/cache"
    "github.com/gorilla/websocket"
    "net/url"
)

// ---------------------------------------------------------------------------------------------------------------------
// Helper structs for managing and closing voice connections
// ---------------------------------------------------------------------------------------------------------------------
var RadioChan *radio.Radio

var RadioCurrentMeta RadioMeta

type RadioMetaContainer struct {
    SongId      float64 `json:"song_id,omitempty"`
    ArtistName  string `json:"artist_name"`
    SongName    string `json:"song_name"`
    AnimeName   string `json:"anime_name,omitempty"`
    RequestedBy string `json:"requested_by,omitempty"`
    Listeners   float64 `json:"listeners,omitempty"`
}

type RadioMeta struct {
    RadioMetaContainer

    Last       RadioMetaContainer `json:"last,omitempty"`
    SecondLast RadioMetaContainer `json:"second_last,omitempty"`
}

type RadioGuildConnection struct {
    sync.RWMutex

    // Closer channel for stop commands
    closer    chan struct{}

    // Marks this guild as streaming music
    streaming bool
}

func (r *RadioGuildConnection) Alloc() *RadioGuildConnection {
    r.Lock()
    r.streaming = false
    r.closer = make(chan struct{})
    r.Unlock()

    return r
}

func (r *RadioGuildConnection) Close() {
    r.Lock()
    close(r.closer)
    r.streaming = false
    r.Unlock()
}

// ---------------------------------------------------------------------------------------------------------------------
// Actual plugin implementation
// ---------------------------------------------------------------------------------------------------------------------
type ListenDotMoe struct {
    connections map[string]*RadioGuildConnection
}

func (l *ListenDotMoe) Commands() []string {
    return []string{
        "moe",
        "lm",
    }
}

func (l *ListenDotMoe) Init(session *discordgo.Session) {
    l.connections = make(map[string]*RadioGuildConnection)

    go l.streamer()
    go l.tracklistWorker()
}

func (l *ListenDotMoe) Action(command string, content string, msg *discordgo.Message, session *discordgo.Session) {
    // Sanitize subcommand
    content = strings.TrimSpace(content)

    // Store channel ref
    channel, err := cache.Channel(msg.ChannelID)
    helpers.Relax(err)

    // Only continue if the voice is available
    if !helpers.VoiceIsFreeOrOccupiedBy(channel.GuildID, "listen.moe") {
        helpers.VoiceSendStatus(channel.ID, channel.GuildID, session)
        return
    }

    // Store guild ref
    guild, err := session.Guild(channel.GuildID)
    helpers.Relax(err)

    // Store voice channel ref
    vc := l.resolveVoiceChannel(msg.Author, guild, session)

    // Store voice connection ref (deferred)
    var voiceConnection *discordgo.VoiceConnection

    // Check if the user is connected to voice at all
    if vc == nil {
        session.ChannelMessageSend(channel.ID, "You're either not in the voice-chat or I can't see you :neutral_face:")
        return
    }

    // He is connected for sure.
    // The routine would've stopped otherwise
    // Check if we are present in this channel too
    if session.VoiceConnections[guild.ID] == nil || session.VoiceConnections[guild.ID].ChannelID != vc.ID {
        // Nope.
        // Check if the user wanted us to join.
        // Else report the error
        if content == "join" {
            helpers.VoiceOccupy(guild.ID, "listen.moe")

            message, merr := session.ChannelMessageSend(channel.ID, ":arrows_counterclockwise: Joining...")

            voiceConnection, err = session.ChannelVoiceJoin(guild.ID, vc.ID, false, false)
            helpers.Relax(err)

            if merr == nil {
                session.ChannelMessageEdit(channel.ID, message.ID, "Joined!\nThe radio should start playing shortly c:")

                l.connections[guild.ID] = (&RadioGuildConnection{}).Alloc()

                go l.pipeStream(guild.ID, session)
                return
            }

            helpers.Relax(merr)
        } else {
            session.ChannelMessageSend(channel.ID, "You should join the channel I'm in or make me join yours before telling me to do stuff :thinking:")
        }

        return
    }

    // We are present.
    // Check for other commands
    switch content {
    case "leave", "l":
        voiceConnection.Disconnect()

        l.connections[guild.ID].Lock()
        l.connections[guild.ID].Close()
        delete(l.connections, guild.ID)

        session.ChannelMessageSend(channel.ID, "OK, bye :frowning:")
        break

    case "playing", "np", "song", "title":
        fields := make([]*discordgo.MessageEmbedField, 1)
        fields[0] = &discordgo.MessageEmbedField{
            Name: "Now Playing",
            Value: RadioCurrentMeta.ArtistName + " " + RadioCurrentMeta.SongName,
            Inline: false,
        }

        if RadioCurrentMeta.AnimeName != "" {
            fields = append(fields, &discordgo.MessageEmbedField{
                Name: "Anime", Value: RadioCurrentMeta.AnimeName, Inline: false,
            })
        }

        if RadioCurrentMeta.RequestedBy != "" {
            fields = append(fields, &discordgo.MessageEmbedField{
                Name: "Requested by", Value: "[" + RadioCurrentMeta.RequestedBy + "](https://forum.listen.moe/u/" + RadioCurrentMeta.RequestedBy + ")", Inline: false,
            })
        }

        session.ChannelMessageSendEmbed(msg.ChannelID, &discordgo.MessageEmbed{
            Color: 0xEC1A55,
            Thumbnail: &discordgo.MessageEmbedThumbnail{
                URL: "http://i.imgur.com/H2cqEio.png",
            },
            Fields: fields,
            Footer: &discordgo.MessageEmbedFooter{
                Text: "powered by listen.moe (ﾉ◕ヮ◕)ﾉ*:･ﾟ✧",
            },
        })
        break
    }
}

// ---------------------------------------------------------------------------------------------------------------------
// Helper functions for managing voice connections
// ---------------------------------------------------------------------------------------------------------------------

// Resolves a voice channel relative to a user id
func (l *ListenDotMoe) resolveVoiceChannel(user *discordgo.User, guild *discordgo.Guild, session *discordgo.Session) *discordgo.Channel {
    for _, vs := range guild.VoiceStates {
        if vs.UserID == user.ID {
            channel, err := session.Channel(vs.ChannelID)
            if err != nil {
                return nil
            }

            return channel
        }
    }

    return nil
}

// ---------------------------------------------------------------------------------------------------------------------
// Helper functions for reading and piping listen.moe's stream to multiple targets at once
// ---------------------------------------------------------------------------------------------------------------------

func (l *ListenDotMoe) streamer() {
    logger.PLUGIN.L("listen_moe", "Allocating channels")
    RadioChan = radio.NewRadio()

    logger.PLUGIN.L("listen_moe", "Piping subprocesses")

    // Read stream with ffmpeg and turn it into PCM
    ffmpeg := exec.Command(
        "ffmpeg",
        "-i", "http://listen.moe:9999/stream",
        "-f", "s16le",
        "pipe:1",
    )
    ffout, err := ffmpeg.StdoutPipe()
    helpers.Relax(err)

    // Pipe FFMPEG to ropus to convert it to .ro format
    ropus := exec.Command("ropus")
    ropus.Stdin = ffout

    rout, err := ropus.StdoutPipe()
    helpers.Relax(err)

    logger.PLUGIN.L("listen_moe", "Running FFMPEG")

    // Run ffmpeg
    err = ffmpeg.Start()
    helpers.Relax(err)

    logger.PLUGIN.L("listen_moe", "Running ROPUS")

    // Run ropus
    err = ropus.Start()
    helpers.Relax(err)

    // Stream ropus to buffer
    robuf := bufio.NewReaderSize(rout, 16384)

    // Stream ropus output to discord
    var opusLength int16

    logger.PLUGIN.L("listen_moe", "Streaming :3")
    for {
        // Read opus frame length
        err = binary.Read(robuf, binary.LittleEndian, &opusLength)
        if err == io.EOF || err == io.ErrUnexpectedEOF {
            break
        }
        helpers.Relax(err)

        // Read audio data
        opus := make([]byte, opusLength)
        err = binary.Read(robuf, binary.LittleEndian, &opus)
        if err == io.EOF || err == io.ErrUnexpectedEOF {
            break
        }
        helpers.Relax(err)

        // Send to discord
        RadioChan.Broadcast(opus)
    }

    logger.PLUGIN.L("listen_moe", "Stream died")
}

func (l *ListenDotMoe) pipeStream(guildID string, session *discordgo.Session) {
    audioChan, id := RadioChan.Listen()
    vc := session.VoiceConnections[guildID]

    vc.Speaking(true)

    // Start eventloop
    for {
        // Exit if the closer channel dies
        select {
        case <-l.connections[guildID].closer:
            return
        default:
        }

        // Do nothing until voice is ready
        if !vc.Ready {
            time.Sleep(1 * time.Second)
            continue
        }

        // Send a frame to discord
        vc.OpusSend <- (<-audioChan)
    }

    vc.Speaking(false)

    RadioChan.Stop(id)
}

// ---------------------------------------------------------------------------------------------------------------------
// Helper functions for interacting with listen.moe's api
// ---------------------------------------------------------------------------------------------------------------------
func (l *ListenDotMoe) tracklistWorker() {
    c, _, err := websocket.DefaultDialer.Dial((&url.URL{
        Scheme: "wss",
        Host: "listen.moe",
        Path: "/api/v2/socket",
    }).String(), nil)

    helpers.Relax(err)
    defer c.Close()

    c.WriteJSON(map[string]string{"token":helpers.GetConfig().Path("listen_moe").Data().(string)})
    helpers.Relax(err)

    for {
        time.Sleep(5 * time.Second)
        logger.VERBOSE.L("listen_moe", "Getting new meta")

        err := c.ReadJSON(&RadioCurrentMeta)
        if err == io.ErrUnexpectedEOF {
            continue
        }
        helpers.Relax(err)
    }
}
<commit_msg>Make the footer of listen.moe a link<commit_after>package plugins

import (
    "time"
    "sync"
    "github.com/sn0w/discordgo"
    "git.lukas.moe/sn0w/Karen/logger"
    "git.lukas.moe/sn0w/Karen/helpers"
    "strings"
    "os/exec"
    "bufio"
    "encoding/binary"
    "io"
    "git.lukas.moe/sn0w/radio-b"
    "git.lukas.moe/sn0w/Karen/cache"
    "github.com/gorilla/websocket"
    "net/url"
)

// ---------------------------------------------------------------------------------------------------------------------
// Helper structs for managing and closing voice connections
// ---------------------------------------------------------------------------------------------------------------------
var RadioChan *radio.Radio

var RadioCurrentMeta RadioMeta

type RadioMetaContainer struct {
    SongId      float64 `json:"song_id,omitempty"`
    ArtistName  string `json:"artist_name"`
    SongName    string `json:"song_name"`
    AnimeName   string `json:"anime_name,omitempty"`
    RequestedBy string `json:"requested_by,omitempty"`
    Listeners   float64 `json:"listeners,omitempty"`
}

type RadioMeta struct {
    RadioMetaContainer

    Last       RadioMetaContainer `json:"last,omitempty"`
    SecondLast RadioMetaContainer `json:"second_last,omitempty"`
}

type RadioGuildConnection struct {
    sync.RWMutex

    // Closer channel for stop commands
    closer    chan struct{}

    // Marks this guild as streaming music
    streaming bool
}

func (r *RadioGuildConnection) Alloc() *RadioGuildConnection {
    r.Lock()
    r.streaming = false
    r.closer = make(chan struct{})
    r.Unlock()

    return r
}

func (r *RadioGuildConnection) Close() {
    r.Lock()
    close(r.closer)
    r.streaming = false
    r.Unlock()
}

// ---------------------------------------------------------------------------------------------------------------------
// Actual plugin implementation
// ---------------------------------------------------------------------------------------------------------------------
type ListenDotMoe struct {
    connections map[string]*RadioGuildConnection
}

func (l *ListenDotMoe) Commands() []string {
    return []string{
        "moe",
        "lm",
    }
}

func (l *ListenDotMoe) Init(session *discordgo.Session) {
    l.connections = make(map[string]*RadioGuildConnection)

    go l.streamer()
    go l.tracklistWorker()
}

func (l *ListenDotMoe) Action(command string, content string, msg *discordgo.Message, session *discordgo.Session) {
    // Sanitize subcommand
    content = strings.TrimSpace(content)

    // Store channel ref
    channel, err := cache.Channel(msg.ChannelID)
    helpers.Relax(err)

    // Only continue if the voice is available
    if !helpers.VoiceIsFreeOrOccupiedBy(channel.GuildID, "listen.moe") {
        helpers.VoiceSendStatus(channel.ID, channel.GuildID, session)
        return
    }

    // Store guild ref
    guild, err := session.Guild(channel.GuildID)
    helpers.Relax(err)

    // Store voice channel ref
    vc := l.resolveVoiceChannel(msg.Author, guild, session)

    // Store voice connection ref (deferred)
    var voiceConnection *discordgo.VoiceConnection

    // Check if the user is connected to voice at all
    if vc == nil {
        session.ChannelMessageSend(channel.ID, "You're either not in the voice-chat or I can't see you :neutral_face:")
        return
    }

    // He is connected for sure.
    // The routine would've stopped otherwise
    // Check if we are present in this channel too
    if session.VoiceConnections[guild.ID] == nil || session.VoiceConnections[guild.ID].ChannelID != vc.ID {
        // Nope.
        // Check if the user wanted us to join.
        // Else report the error
        if content == "join" {
            helpers.VoiceOccupy(guild.ID, "listen.moe")

            message, merr := session.ChannelMessageSend(channel.ID, ":arrows_counterclockwise: Joining...")

            voiceConnection, err = session.ChannelVoiceJoin(guild.ID, vc.ID, false, false)
            helpers.Relax(err)

            if merr == nil {
                session.ChannelMessageEdit(channel.ID, message.ID, "Joined!\nThe radio should start playing shortly c:")

                l.connections[guild.ID] = (&RadioGuildConnection{}).Alloc()

                go l.pipeStream(guild.ID, session)
                return
            }

            helpers.Relax(merr)
        } else {
            session.ChannelMessageSend(channel.ID, "You should join the channel I'm in or make me join yours before telling me to do stuff :thinking:")
        }

        return
    }

    // We are present.
    // Check for other commands
    switch content {
    case "leave", "l":
        voiceConnection.Disconnect()

        l.connections[guild.ID].Lock()
        l.connections[guild.ID].Close()
        delete(l.connections, guild.ID)

        session.ChannelMessageSend(channel.ID, "OK, bye :frowning:")
        break

    case "playing", "np", "song", "title":
        fields := make([]*discordgo.MessageEmbedField, 1)
        fields[0] = &discordgo.MessageEmbedField{
            Name: "Now Playing",
            Value: RadioCurrentMeta.ArtistName + " " + RadioCurrentMeta.SongName,
            Inline: false,
        }

        if RadioCurrentMeta.AnimeName != "" {
            fields = append(fields, &discordgo.MessageEmbedField{
                Name: "Anime", Value: RadioCurrentMeta.AnimeName, Inline: false,
            })
        }

        if RadioCurrentMeta.RequestedBy != "" {
            fields = append(fields, &discordgo.MessageEmbedField{
                Name: "Requested by", Value: "[" + RadioCurrentMeta.RequestedBy + "](https://forum.listen.moe/u/" + RadioCurrentMeta.RequestedBy + ")", Inline: false,
            })
        }

        session.ChannelMessageSendEmbed(msg.ChannelID, &discordgo.MessageEmbed{
            Color: 0xEC1A55,
            Thumbnail: &discordgo.MessageEmbedThumbnail{
                URL: "http://i.imgur.com/H2cqEio.png",
            },
            Fields: fields,
            Footer: &discordgo.MessageEmbedFooter{
                Text: "powered by [listen.moe](https://listen.moe) (ﾉ◕ヮ◕)ﾉ*:･ﾟ✧",
            },
        })
        break
    }
}

// ---------------------------------------------------------------------------------------------------------------------
// Helper functions for managing voice connections
// ---------------------------------------------------------------------------------------------------------------------

// Resolves a voice channel relative to a user id
func (l *ListenDotMoe) resolveVoiceChannel(user *discordgo.User, guild *discordgo.Guild, session *discordgo.Session) *discordgo.Channel {
    for _, vs := range guild.VoiceStates {
        if vs.UserID == user.ID {
            channel, err := session.Channel(vs.ChannelID)
            if err != nil {
                return nil
            }

            return channel
        }
    }

    return nil
}

// ---------------------------------------------------------------------------------------------------------------------
// Helper functions for reading and piping listen.moe's stream to multiple targets at once
// ---------------------------------------------------------------------------------------------------------------------

func (l *ListenDotMoe) streamer() {
    logger.PLUGIN.L("listen_moe", "Allocating channels")
    RadioChan = radio.NewRadio()

    logger.PLUGIN.L("listen_moe", "Piping subprocesses")

    // Read stream with ffmpeg and turn it into PCM
    ffmpeg := exec.Command(
        "ffmpeg",
        "-i", "http://listen.moe:9999/stream",
        "-f", "s16le",
        "pipe:1",
    )
    ffout, err := ffmpeg.StdoutPipe()
    helpers.Relax(err)

    // Pipe FFMPEG to ropus to convert it to .ro format
    ropus := exec.Command("ropus")
    ropus.Stdin = ffout

    rout, err := ropus.StdoutPipe()
    helpers.Relax(err)

    logger.PLUGIN.L("listen_moe", "Running FFMPEG")

    // Run ffmpeg
    err = ffmpeg.Start()
    helpers.Relax(err)

    logger.PLUGIN.L("listen_moe", "Running ROPUS")

    // Run ropus
    err = ropus.Start()
    helpers.Relax(err)

    // Stream ropus to buffer
    robuf := bufio.NewReaderSize(rout, 16384)

    // Stream ropus output to discord
    var opusLength int16

    logger.PLUGIN.L("listen_moe", "Streaming :3")
    for {
        // Read opus frame length
        err = binary.Read(robuf, binary.LittleEndian, &opusLength)
        if err == io.EOF || err == io.ErrUnexpectedEOF {
            break
        }
        helpers.Relax(err)

        // Read audio data
        opus := make([]byte, opusLength)
        err = binary.Read(robuf, binary.LittleEndian, &opus)
        if err == io.EOF || err == io.ErrUnexpectedEOF {
            break
        }
        helpers.Relax(err)

        // Send to discord
        RadioChan.Broadcast(opus)
    }

    logger.PLUGIN.L("listen_moe", "Stream died")
}

func (l *ListenDotMoe) pipeStream(guildID string, session *discordgo.Session) {
    audioChan, id := RadioChan.Listen()
    vc := session.VoiceConnections[guildID]

    vc.Speaking(true)

    // Start eventloop
    for {
        // Exit if the closer channel dies
        select {
        case <-l.connections[guildID].closer:
            return
        default:
        }

        // Do nothing until voice is ready
        if !vc.Ready {
            time.Sleep(1 * time.Second)
            continue
        }

        // Send a frame to discord
        vc.OpusSend <- (<-audioChan)
    }

    vc.Speaking(false)

    RadioChan.Stop(id)
}

// ---------------------------------------------------------------------------------------------------------------------
// Helper functions for interacting with listen.moe's api
// ---------------------------------------------------------------------------------------------------------------------
func (l *ListenDotMoe) tracklistWorker() {
    c, _, err := websocket.DefaultDialer.Dial((&url.URL{
        Scheme: "wss",
        Host: "listen.moe",
        Path: "/api/v2/socket",
    }).String(), nil)

    helpers.Relax(err)
    defer c.Close()

    c.WriteJSON(map[string]string{"token":helpers.GetConfig().Path("listen_moe").Data().(string)})
    helpers.Relax(err)

    for {
        time.Sleep(5 * time.Second)
        err := c.ReadJSON(&RadioCurrentMeta)
        if err == io.ErrUnexpectedEOF {
            continue
        }
        helpers.Relax(err)
    }
}
<|endoftext|>


<commit_before>package proto

import (
	"testing"
	"time"
)

func TestSHA1(t *testing.T) {
	if len(GitSHA()) != 40 {
		t.Errorf("len(GitSHA()) == %d, %d != 40", len(GitSHA()), len(GitSHA()))
	}
}

func TestX(t *testing.T) {
	if GitTime().After(time.Now()) {
		t.Errorf("GitTime() is %v, which is in the future", GitTime())
	}
}
<commit_msg>Fix function names.<commit_after>package proto

import (
	"testing"
	"time"
)

func TestSHA(t *testing.T) {
	if len(GitSHA()) != 40 {
		t.Errorf("len(GitSHA()) == %d, %d != 40", len(GitSHA()), len(GitSHA()))
	}
}

func TestTime(t *testing.T) {
	if GitTime().After(time.Now()) {
		t.Errorf("GitTime() is %v, which is in the future", GitTime())
	}
}
<|endoftext|>


<commit_before>package epub

import (
  "encoding/xml"
  "log"
)

const (
	navBodyTemplate = `

Table of Contents

Section 1

`
	navDocFilename = "nav.xhtml"
	xmlnsEpub      = `xmlns:epub="http://www.idpf.org/2007/ops"`
)

type tocXmlNav struct {
    XMLName xml.Name `xml:"http://www.w3.org/1999/xhtml html"`
    H1 string `xml:"h1"`
//    A tocXmlNav
}

type toc struct {
	navDoc *xhtml
}

func newToc() (*toc, error) {
	t := &toc{}
	t.navDoc = &xhtml{}

  output, err := xml.MarshalIndent(t.navDoc, "", `   `)
  log.Println(string(output))

  err = xml.Unmarshal([]byte(xhtmlTemplate), &t.navDoc)
  if err != nil {
    log.Println("xml.Unmarshal error: %s", err)
  }

  output, err = xml.MarshalIndent(t.navDoc, "", `   `)
  log.Println(string(output))

  t.navDoc.setBody(navBodyTemplate)

  output, err = xml.MarshalIndent(t.navDoc, "", `   `)
  log.Println(string(output))

	return t, err
}

/*
func (t *toc) write() {
	contentFolderPath := filepath.Join(tempDir, contentFolderName)

	navDocFilePath := filepath.Join(contentFolderPath, navDocFilename)

	output, err := xml.MarshalIndent(e.pkgdoc, "", `   `)
	if err != nil {
		return err
	}
	// Add the xml header to the output
	pkgdocFileContent := append([]byte(xml.Header), output...)
	// It's generally nice to have files end with a newline
	pkgdocFileContent = append(pkgdocFileContent, "\n"...)

	if err := ioutil.WriteFile(pkgdocFilePath, []byte(pkgdocFileContent), filePermissions); err != nil {
		return err
	}

	return nil
}
*/<commit_msg>Get nav doc body stuff working<commit_after>package epub

import (
  "encoding/xml"
  "log"
)

const (
    navDocBodyTemplate = `

Table of Contents

`
    navDocFilename = "nav.xhtml"
    navDocEpubType = "toc"
    xmlnsEpub      = `xmlns:epub="http://www.idpf.org/2007/ops"`
)

type tocXmlNavLink struct {
    A struct {
        XMLName xml.Name `xml:"a"`
        Href string `xml:"href,attr"`
        Data string `xml:",chardata"`
    } `xml:a`
}

type tocXmlNav struct {
    XMLName xml.Name `xml:"nav"`
    EpubType string `xml:"epub:type,attr"`
    H1 string `xml:"h1"`
    Links []tocXmlNavLink `xml:"ol>li"`
}

type toc struct {
	navDoc *xhtml
}

func newToc() (*toc, error) {
	t := &toc{}
	t.navDoc = &xhtml{}

  output, err := xml.MarshalIndent(t.navDoc, "", `   `)
  log.Println(string(output))

  err = xml.Unmarshal([]byte(xhtmlTemplate), &t.navDoc)
  if err != nil {
    log.Println("xml.Unmarshal error: %s", err)
  }

  output, err = xml.MarshalIndent(t.navDoc, "", `   `)
  log.Println(string(output))

//  t.navDoc.setBody(navDocTemplate)

    n := &tocXmlNav{
        EpubType: navDocEpubType,
    }
  err = xml.Unmarshal([]byte(navDocBodyTemplate), &n)
  if err != nil {
    log.Println("xml.Unmarshal error: %s", err)
  }

	navDocBodyContent, err := xml.MarshalIndent(n, "", `   `)
  if err != nil {
    log.Println("xml.Unmarshal error: %s", err)
  }
  log.Println(string(navDocBodyContent))

    t.navDoc.setBody(string(navDocBodyContent))

  output, err = xml.MarshalIndent(t.navDoc, "", `   `)
  log.Println(string(output))

	return t, err
}

/*
func (t *toc) write() {
	contentFolderPath := filepath.Join(tempDir, contentFolderName)

	navDocFilePath := filepath.Join(contentFolderPath, navDocFilename)

	output, err := xml.MarshalIndent(e.pkgdoc, "", `   `)
	if err != nil {
		return err
	}
	// Add the xml header to the output
	pkgdocFileContent := append([]byte(xml.Header), output...)
	// It's generally nice to have files end with a newline
	pkgdocFileContent = append(pkgdocFileContent, "\n"...)

	if err := ioutil.WriteFile(pkgdocFilePath, []byte(pkgdocFileContent), filePermissions); err != nil {
		return err
	}

	return nil
}
*/<|endoftext|>


<commit_before>package protocol

import (
	"bytes"
	"encoding/binary"
	"strconv"
)

// VersionNumber is a version number as int
type VersionNumber int

// The version numbers, making grepping easier
const (
	Version32 VersionNumber = 32 + iota
	Version33
	Version34
	Version35
	VersionWhatever = 0 // for when the version doesn't matter
)

// SupportedVersions lists the versions that the server supports
var SupportedVersions = []VersionNumber{
	Version33, Version34, Version35,
}

// SupportedVersionsAsTags is needed for the SHLO crypto message
var SupportedVersionsAsTags []byte

// SupportedVersionsAsString is needed for the Alt-Scv HTTP header
var SupportedVersionsAsString string

// VersionNumberToTag maps version numbers ('32') to tags ('Q032')
func VersionNumberToTag(vn VersionNumber) uint32 {
	v := uint32(vn)
	return 'Q' + ((v/100%10)+'0')<<8 + ((v/10%10)+'0')<<16 + ((v%10)+'0')<<24
}

// VersionTagToNumber is built from VersionNumberToTag in init()
func VersionTagToNumber(v uint32) VersionNumber {
	return VersionNumber(((v>>8)&0xff-'0')*100 + ((v>>16)&0xff-'0')*10 + ((v>>24)&0xff - '0'))
}

// IsSupportedVersion returns true if the server supports this version
func IsSupportedVersion(v VersionNumber) bool {
	for _, t := range SupportedVersions {
		if t == v {
			return true
		}
	}
	return false
}

func init() {
	var b bytes.Buffer
	for _, v := range SupportedVersions {
		s := make([]byte, 4)
		binary.LittleEndian.PutUint32(s, VersionNumberToTag(v))
		b.Write(s)
	}
	SupportedVersionsAsTags = b.Bytes()

	for i := len(SupportedVersions) - 1; i >= 0; i-- {
		SupportedVersionsAsString += strconv.Itoa(int(SupportedVersions[i]))
		if i != 0 {
			SupportedVersionsAsString += ","
		}
	}
}
<commit_msg>remove Version32 const<commit_after>package protocol

import (
	"bytes"
	"encoding/binary"
	"strconv"
)

// VersionNumber is a version number as int
type VersionNumber int

// The version numbers, making grepping easier
const (
	Version33 VersionNumber = 33 + iota
	Version34
	Version35
	VersionWhatever = 0 // for when the version doesn't matter
)

// SupportedVersions lists the versions that the server supports
var SupportedVersions = []VersionNumber{
	Version33, Version34, Version35,
}

// SupportedVersionsAsTags is needed for the SHLO crypto message
var SupportedVersionsAsTags []byte

// SupportedVersionsAsString is needed for the Alt-Scv HTTP header
var SupportedVersionsAsString string

// VersionNumberToTag maps version numbers ('32') to tags ('Q032')
func VersionNumberToTag(vn VersionNumber) uint32 {
	v := uint32(vn)
	return 'Q' + ((v/100%10)+'0')<<8 + ((v/10%10)+'0')<<16 + ((v%10)+'0')<<24
}

// VersionTagToNumber is built from VersionNumberToTag in init()
func VersionTagToNumber(v uint32) VersionNumber {
	return VersionNumber(((v>>8)&0xff-'0')*100 + ((v>>16)&0xff-'0')*10 + ((v>>24)&0xff - '0'))
}

// IsSupportedVersion returns true if the server supports this version
func IsSupportedVersion(v VersionNumber) bool {
	for _, t := range SupportedVersions {
		if t == v {
			return true
		}
	}
	return false
}

func init() {
	var b bytes.Buffer
	for _, v := range SupportedVersions {
		s := make([]byte, 4)
		binary.LittleEndian.PutUint32(s, VersionNumberToTag(v))
		b.Write(s)
	}
	SupportedVersionsAsTags = b.Bytes()

	for i := len(SupportedVersions) - 1; i >= 0; i-- {
		SupportedVersionsAsString += strconv.Itoa(int(SupportedVersions[i]))
		if i != 0 {
			SupportedVersionsAsString += ","
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"sort"
	"strings"
	"time"

	"github.com/kylelemons/go-gypsy/yaml"
)

// Default configuration file
var conffile = flag.String("c", ".tsmrc", "config file")
var showAllBackups = flag.Bool("with-current", false, "list-expired: list current backups too")

// Config variables. Provide a default for tarsnap(1) path.
var cfgTarsnapBin = "/usr/local/bin/tarsnap"
var cfgTarsnapArgs []string
var cfgBackupDirs []string
var cfgExcludeFile string

// Templates for time.Parse()
const iso8601 = "2006-01-02"
const nightly = "nightly-2006-01-02"
const adhoc = "adhoc-2006-01-02_1504"

const day = time.Hour * 24

var info = log.New(os.Stdout, "", log.LstdFlags)

// Shamefully "borrowed" from src/cmd/go/main.go
// Flattens a mix of strings and slices of strings into a single slice.
func commandArgs(args ...interface{}) []string {
	var x []string
	for _, arg := range args {
		switch arg := arg.(type) {
		case []string:
			x = append(x, arg...)
		case string:
			x = append(x, arg)
		default:
			panic("commandArgs: invalid argument")
		}
	}
	return x
}

// Creates a new Tarsnap archive
func runBackup(archiveName string) {
	info.Printf("Starting backup %s\n", archiveName)
	args := commandArgs("-c", "-f", archiveName, cfgTarsnapArgs, cfgBackupDirs)
	backup := exec.Command(cfgTarsnapBin, args...)
	backup.Stdout = os.Stdout
	backup.Stderr = os.Stderr
	backuperr := backup.Run()
	if backuperr != nil {
		log.Fatal("Error running backup: ", backuperr)
	}
	info.Println("Backup finished")
}

// Deletes a Tarsnap archive
func deleteBackup(backup string) {
	deletecmd := exec.Command(cfgTarsnapBin, "-d", "-f", backup)
	deletecmd.Stdout = os.Stdout
	deletecmd.Stderr = os.Stderr
	err := deletecmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}

// Runs expiry against backup archives
func expireBackups(w, m time.Time, reallyExpire bool) {
	listcmd := exec.Command(cfgTarsnapBin, "--list-archives")
	var stdout bytes.Buffer
	listcmd.Stdout = &stdout
	listcmd.Stderr = os.Stderr
	listerr := listcmd.Run()
	if listerr != nil {
		log.Fatal("Error running command: ", listerr)
	}
	backups := strings.Split(strings.TrimSuffix(stdout.String(), "\n"), "\n")
	sort.Strings(backups)

	for i := 0; i < len(backups); i++ {
		// Don't expire adhoc backups
		if strings.HasPrefix(backups[i], "adhoc-") {
			continue
		}
		backup, _ := time.Parse(nightly, backups[i])
		eom := time.Date(backup.Year(), backup.Month()+1, 0, 0, 0, 0, 0, backup.Location())
		if (backup.Before(w) && backup.Day() != eom.Day()) || backup.Before(m) {
			if reallyExpire {
				info.Println("Expiring backup", backups[i])
				deleteBackup(backups[i])
			} else {
				fmt.Println("Expired backup", backups[i])
			}
		} else {
			if *showAllBackups && !reallyExpire {
				fmt.Println("Current backup", backups[i])
			}
		}
	}
}

func main() {
	flag.Parse()

	config, conferr := yaml.ReadFile(*conffile)
	if conferr != nil {
		log.Fatalf("Error reading config %q: %s", *conffile, conferr)
	}

	tmpTarsnapBin, _ := config.Get("TarsnapBin")
	if tmpTarsnapBin != "" {
		cfgTarsnapBin = tmpTarsnapBin
	}

	count, err := config.Count("TarsnapArgs")
	for i := 0; i < count; i++ {
		s := fmt.Sprintf("TarsnapArgs[%d]", i)
		t, err := config.Get(s)
		if err != nil {
			log.Fatal(err)
		}
		// Remove any quotes from the arg - used to protect
		// options (starting with a -)
		t = strings.Replace(t, `"`, ``, -1)
		cfgTarsnapArgs = append(cfgTarsnapArgs, t)
	}

	count, err = config.Count("BackupDirs")
	if err != nil {
		fmt.Println("No backup directories specified")
		os.Exit(1)
	}
	for i := 0; i < count; i++ {
		s := fmt.Sprintf("BackupDirs[%d]", i)
		t, err := config.Get(s)
		if err != nil {
			log.Fatal(err)
		}
		cfgBackupDirs = append(cfgBackupDirs, t)
	}

	cfgExcludeFile, err := config.Get("ExcludeFile")
	if err == nil {
		cfgTarsnapArgs = append(cfgTarsnapArgs, "-X", cfgExcludeFile)
	}

	// GetInt() returns an int64. Convert this to an int.
	tmpKeepWeeks, err := config.GetInt("KeepWeeks")
	if err != nil {
		fmt.Println("Missing config value KeepWeeks")
		os.Exit(1)
	}
	tmpKeepMonths, err := config.GetInt("KeepMonths")
	if err != nil {
		fmt.Println("Missing config value KeepMonths")
		os.Exit(1)
	}
	cfgKeepWeeks := int(tmpKeepWeeks)
	cfgKeepMonths := int(tmpKeepMonths)

	t := time.Now()
	w := t.AddDate(0, 0, -(7 * cfgKeepWeeks))
	m := t.AddDate(0, -cfgKeepMonths, 0)
	fmt.Printf("Date: %s\nExpire week: %s\nExpire month: %s\n\n", t.Format(iso8601), w.Format(iso8601), m.Format(iso8601))

	if len(os.Args) < 2 {
		fmt.Println("Missing action")
		os.Exit(1)
	}
	action := flag.Args()[0]
	switch action {
	case "nightly":
		// Run nightly
		runBackup(t.Format(nightly))

		// TODO: Make w and m global?
		cfgExpireBackups, _ := config.GetBool("ExpireBackups")
		if cfgExpireBackups {
			expireBackups(w, m, true)
		} else {
			info.Println("Backup expiration disabled")
		}

		info.Println("All done!")
	case "adhoc":
		// Run adhoc
		runBackup(t.Format(adhoc))
	case "list-expired":
		expireBackups(w, m, false)
	default:
		log.Fatalf("Unknown action '%s'", action)
	}
}
<commit_msg>Use flag.Args() instead of os.Args<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"sort"
	"strings"
	"time"

	"github.com/kylelemons/go-gypsy/yaml"
)

// Default configuration file
var conffile = flag.String("c", ".tsmrc", "config file")
var showAllBackups = flag.Bool("with-current", false, "list-expired: list current backups too")

// Config variables. Provide a default for tarsnap(1) path.
var cfgTarsnapBin = "/usr/local/bin/tarsnap"
var cfgTarsnapArgs []string
var cfgBackupDirs []string
var cfgExcludeFile string

// Templates for time.Parse()
const iso8601 = "2006-01-02"
const nightly = "nightly-2006-01-02"
const adhoc = "adhoc-2006-01-02_1504"

const day = time.Hour * 24

var info = log.New(os.Stdout, "", log.LstdFlags)

// Shamefully "borrowed" from src/cmd/go/main.go
// Flattens a mix of strings and slices of strings into a single slice.
func commandArgs(args ...interface{}) []string {
	var x []string
	for _, arg := range args {
		switch arg := arg.(type) {
		case []string:
			x = append(x, arg...)
		case string:
			x = append(x, arg)
		default:
			panic("commandArgs: invalid argument")
		}
	}
	return x
}

// Creates a new Tarsnap archive
func runBackup(archiveName string) {
	info.Printf("Starting backup %s\n", archiveName)
	args := commandArgs("-c", "-f", archiveName, cfgTarsnapArgs, cfgBackupDirs)
	backup := exec.Command(cfgTarsnapBin, args...)
	backup.Stdout = os.Stdout
	backup.Stderr = os.Stderr
	backuperr := backup.Run()
	if backuperr != nil {
		log.Fatal("Error running backup: ", backuperr)
	}
	info.Println("Backup finished")
}

// Deletes a Tarsnap archive
func deleteBackup(backup string) {
	deletecmd := exec.Command(cfgTarsnapBin, "-d", "-f", backup)
	deletecmd.Stdout = os.Stdout
	deletecmd.Stderr = os.Stderr
	err := deletecmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}

// Runs expiry against backup archives
func expireBackups(w, m time.Time, reallyExpire bool) {
	listcmd := exec.Command(cfgTarsnapBin, "--list-archives")
	var stdout bytes.Buffer
	listcmd.Stdout = &stdout
	listcmd.Stderr = os.Stderr
	listerr := listcmd.Run()
	if listerr != nil {
		log.Fatal("Error running command: ", listerr)
	}
	backups := strings.Split(strings.TrimSuffix(stdout.String(), "\n"), "\n")
	sort.Strings(backups)

	for i := 0; i < len(backups); i++ {
		// Don't expire adhoc backups
		if strings.HasPrefix(backups[i], "adhoc-") {
			continue
		}
		backup, _ := time.Parse(nightly, backups[i])
		eom := time.Date(backup.Year(), backup.Month()+1, 0, 0, 0, 0, 0, backup.Location())
		if (backup.Before(w) && backup.Day() != eom.Day()) || backup.Before(m) {
			if reallyExpire {
				info.Println("Expiring backup", backups[i])
				deleteBackup(backups[i])
			} else {
				fmt.Println("Expired backup", backups[i])
			}
		} else {
			if *showAllBackups && !reallyExpire {
				fmt.Println("Current backup", backups[i])
			}
		}
	}
}

func main() {
	flag.Parse()

	config, conferr := yaml.ReadFile(*conffile)
	if conferr != nil {
		log.Fatalf("Error reading config %q: %s", *conffile, conferr)
	}

	tmpTarsnapBin, _ := config.Get("TarsnapBin")
	if tmpTarsnapBin != "" {
		cfgTarsnapBin = tmpTarsnapBin
	}

	count, err := config.Count("TarsnapArgs")
	for i := 0; i < count; i++ {
		s := fmt.Sprintf("TarsnapArgs[%d]", i)
		t, err := config.Get(s)
		if err != nil {
			log.Fatal(err)
		}
		// Remove any quotes from the arg - used to protect
		// options (starting with a -)
		t = strings.Replace(t, `"`, ``, -1)
		cfgTarsnapArgs = append(cfgTarsnapArgs, t)
	}

	count, err = config.Count("BackupDirs")
	if err != nil {
		fmt.Println("No backup directories specified")
		os.Exit(1)
	}
	for i := 0; i < count; i++ {
		s := fmt.Sprintf("BackupDirs[%d]", i)
		t, err := config.Get(s)
		if err != nil {
			log.Fatal(err)
		}
		cfgBackupDirs = append(cfgBackupDirs, t)
	}

	cfgExcludeFile, err := config.Get("ExcludeFile")
	if err == nil {
		cfgTarsnapArgs = append(cfgTarsnapArgs, "-X", cfgExcludeFile)
	}

	// GetInt() returns an int64. Convert this to an int.
	tmpKeepWeeks, err := config.GetInt("KeepWeeks")
	if err != nil {
		fmt.Println("Missing config value KeepWeeks")
		os.Exit(1)
	}
	tmpKeepMonths, err := config.GetInt("KeepMonths")
	if err != nil {
		fmt.Println("Missing config value KeepMonths")
		os.Exit(1)
	}
	cfgKeepWeeks := int(tmpKeepWeeks)
	cfgKeepMonths := int(tmpKeepMonths)

	t := time.Now()
	w := t.AddDate(0, 0, -(7 * cfgKeepWeeks))
	m := t.AddDate(0, -cfgKeepMonths, 0)
	fmt.Printf("Date: %s\nExpire week: %s\nExpire month: %s\n\n", t.Format(iso8601), w.Format(iso8601), m.Format(iso8601))

	if len(flag.Args()) == 0 {
		fmt.Println("Missing action")
		os.Exit(1)
	}
	action := flag.Args()[0]
	switch action {
	case "nightly":
		// Run nightly
		runBackup(t.Format(nightly))

		// TODO: Make w and m global?
		cfgExpireBackups, _ := config.GetBool("ExpireBackups")
		if cfgExpireBackups {
			expireBackups(w, m, true)
		} else {
			info.Println("Backup expiration disabled")
		}

		info.Println("All done!")
	case "adhoc":
		// Run adhoc
		runBackup(t.Format(adhoc))
	case "list-expired":
		expireBackups(w, m, false)
	default:
		log.Fatalf("Unknown action '%s'", action)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"strconv"

	api "github.com/gophergala2016/be/insightapi"
	"github.com/gophergala2016/be/tui"
	"github.com/nsf/termbox-go"
)

var (
	state api.BlockList
)

const (
	boxWidth  = 19
	boxHeight = 7
	xMargin   = 2
	yMargin   = 1
	xSpace    = 4
	ySpace    = 2
)

func tuiLatestBlocks() {
	var err error
	state, err = api.GetLatestBlocks()
	if err != nil {
		log.Fatal(err)
	}

	err = termbox.Init()
	if err != nil {
		log.Fatal(err)
	}
	defer termbox.Close()

	draw()
	tuiPoll()
}

func box(lines []string, x, y int, background termbox.Attribute) tui.Box {
	return tui.Box{
		Lines: lines,
		X:     xMargin + x*(boxWidth+xSpace), Y: yMargin + y*(boxHeight+ySpace),
		Width: boxWidth, Height: boxHeight,
		Background: background, Foreground: termbox.ColorBlack,
	}
}

func horizontalLine(x, y int) tui.Box {
	line := ""
	if y%2 != 0 {
		line = line + "<"
	}
	for i := 0; i < xSpace-1; i++ {
		line = line + "─"
	}
	if y%2 == 0 {
		line = line + ">"
	}

	return tui.Box{
		Lines: []string{line},
		X:     xMargin + boxWidth + (xSpace+boxWidth)*x,
		Y:     yMargin + boxHeight/2 + (ySpace+boxHeight)*y,
		Width: xSpace, Height: 1,
		Foreground: termbox.ColorWhite,
	}
}

func verticalLine(x, y int) tui.Box {
	lines := []string{}
	for i := 0; i < ySpace-1; i++ {
		lines = append(lines, "│")
	}
	lines = append(lines, "v")

	return tui.Box{
		Lines: lines,
		X:     xMargin + boxWidth/2 + (xSpace+boxWidth)*x,
		Y:     yMargin + boxHeight + (ySpace+boxHeight)*y,
		Width: 1, Height: ySpace,
		Foreground: termbox.ColorWhite,
	}
}

func calculateFit(pad, space, boxSize, containerSize int) (boxes int) {
	for {
		if pad+boxSize*(boxes+1)+space*boxes+pad > containerSize {
			return
		}

		boxes = boxes + 1
	}
}

func blockBox(block api.BlockInfo, i int) tui.Group {
	containerWidth, _ := termbox.Size()

	xBoxes := calculateFit(xMargin, xSpace, boxWidth, containerWidth)

	y := i / xBoxes

	var x int

	if y%2 == 0 {
		x = i % xBoxes
	} else {
		x = xBoxes - 1 - (i % xBoxes)
	}

	box := box(
		[]string{
			"",
			"  #" + strconv.Itoa(block.Height),
			"",
			"  " + strconv.Itoa(block.Txlength) + "txs",
			"  " + strconv.Itoa(block.Size/1024) + "kb",
			"  " + block.PoolInfo.PoolName,
		},
		x, y, termbox.ColorBlue,
	)

	var line tui.Drawable

	if y%2 == 0 {
		if x == 0 {
			line = verticalLine(x, y-1)
		} else {
			line = horizontalLine(x-1, y)
		}
	} else {
		if x == xBoxes-1 {
			line = verticalLine(x, y-1)
		} else {
			line = horizontalLine(x, y)
		}
	}

	return tui.Group{box, line}
}

func nextBlockBox(block api.BlockInfo) tui.Box {
	return box(
		[]string{
			"",
			"  #" + strconv.Itoa(block.Height+1),
			"",
			"  next",
			"  block",
		},
		0, 0, termbox.ColorRed,
	)
}

func draw() {
	canvas := tui.Canvas{}

	group := tui.Group{}
	for i, block := range state.Blocks {
		if i == 0 { // draw unconfirmed block
			group = append(group, nextBlockBox(block))
		}

		group = append(group, blockBox(block, i+1))
	}

	canvas.Drawable = group
	canvas.Redraw()
}

func tuiPoll() {
	for {
		e := termbox.PollEvent()

		if e.Type == termbox.EventKey {
			return
		}

		if e.Type == termbox.EventResize {
			draw()
		}
	}
}
<commit_msg>Capital V!<commit_after>package main

import (
	"log"
	"strconv"

	api "github.com/gophergala2016/be/insightapi"
	"github.com/gophergala2016/be/tui"
	"github.com/nsf/termbox-go"
)

var (
	state api.BlockList
)

const (
	boxWidth  = 19
	boxHeight = 7
	xMargin   = 2
	yMargin   = 1
	xSpace    = 4
	ySpace    = 2
)

func tuiLatestBlocks() {
	var err error
	state, err = api.GetLatestBlocks()
	if err != nil {
		log.Fatal(err)
	}

	err = termbox.Init()
	if err != nil {
		log.Fatal(err)
	}
	defer termbox.Close()

	draw()
	tuiPoll()
}

func box(lines []string, x, y int, background termbox.Attribute) tui.Box {
	return tui.Box{
		Lines: lines,
		X:     xMargin + x*(boxWidth+xSpace), Y: yMargin + y*(boxHeight+ySpace),
		Width: boxWidth, Height: boxHeight,
		Background: background, Foreground: termbox.ColorBlack,
	}
}

func horizontalLine(x, y int) tui.Box {
	line := ""
	if y%2 != 0 {
		line = line + "<"
	}
	for i := 0; i < xSpace-1; i++ {
		line = line + "─"
	}
	if y%2 == 0 {
		line = line + ">"
	}

	return tui.Box{
		Lines: []string{line},
		X:     xMargin + boxWidth + (xSpace+boxWidth)*x,
		Y:     yMargin + boxHeight/2 + (ySpace+boxHeight)*y,
		Width: xSpace, Height: 1,
		Foreground: termbox.ColorWhite,
	}
}

func verticalLine(x, y int) tui.Box {
	lines := []string{}
	for i := 0; i < ySpace-1; i++ {
		lines = append(lines, "│")
	}
	lines = append(lines, "V")

	return tui.Box{
		Lines: lines,
		X:     xMargin + boxWidth/2 + (xSpace+boxWidth)*x,
		Y:     yMargin + boxHeight + (ySpace+boxHeight)*y,
		Width: 1, Height: ySpace,
		Foreground: termbox.ColorWhite,
	}
}

func calculateFit(pad, space, boxSize, containerSize int) (boxes int) {
	for {
		if pad+boxSize*(boxes+1)+space*boxes+pad > containerSize {
			return
		}

		boxes = boxes + 1
	}
}

func blockBox(block api.BlockInfo, i int) tui.Group {
	containerWidth, _ := termbox.Size()

	xBoxes := calculateFit(xMargin, xSpace, boxWidth, containerWidth)

	y := i / xBoxes

	var x int

	if y%2 == 0 {
		x = i % xBoxes
	} else {
		x = xBoxes - 1 - (i % xBoxes)
	}

	box := box(
		[]string{
			"",
			"  #" + strconv.Itoa(block.Height),
			"",
			"  " + strconv.Itoa(block.Txlength) + "txs",
			"  " + strconv.Itoa(block.Size/1024) + "kb",
			"  " + block.PoolInfo.PoolName,
		},
		x, y, termbox.ColorBlue,
	)

	var line tui.Drawable

	if y%2 == 0 {
		if x == 0 {
			line = verticalLine(x, y-1)
		} else {
			line = horizontalLine(x-1, y)
		}
	} else {
		if x == xBoxes-1 {
			line = verticalLine(x, y-1)
		} else {
			line = horizontalLine(x, y)
		}
	}

	return tui.Group{box, line}
}

func nextBlockBox(block api.BlockInfo) tui.Box {
	return box(
		[]string{
			"",
			"  #" + strconv.Itoa(block.Height+1),
			"",
			"  next",
			"  block",
		},
		0, 0, termbox.ColorRed,
	)
}

func draw() {
	canvas := tui.Canvas{}

	group := tui.Group{}
	for i, block := range state.Blocks {
		if i == 0 { // draw unconfirmed block
			group = append(group, nextBlockBox(block))
		}

		group = append(group, blockBox(block, i+1))
	}

	canvas.Drawable = group
	canvas.Redraw()
}

func tuiPoll() {
	for {
		e := termbox.PollEvent()

		if e.Type == termbox.EventKey {
			return
		}

		if e.Type == termbox.EventResize {
			draw()
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package gce

import (
	"net/http"
	"net/mail"
	"time"

	"code.google.com/p/goauth2/oauth"
	"code.google.com/p/goauth2/oauth/jwt"
	"code.google.com/p/google-api-go-client/compute/v1"
	"github.com/juju/errors"
	"github.com/juju/utils"

	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/network"
	"github.com/juju/juju/provider/common"
)

const (
	driverScopes = "https://www.googleapis.com/auth/compute " +
		"https://www.googleapis.com/auth/devstorage.full_control"

	tokenURL = "https://accounts.google.com/o/oauth2/token"

	authURL = "https://accounts.google.com/o/oauth2/auth"

	partialMachineType = "zones/%s/machineTypes/%s"

	diskTypeScratch    = "SCRATCH"
	diskTypePersistent = "PERSISTENT"
	diskModeRW         = "READ_WRITE"
	diskModeRO         = "READ_ONLY"

	statusDone         = "DONE"
	statusDown         = "DOWN"
	statusPending      = "PENDING"
	statusProvisioning = "PROVISIONING"
	statusRunning      = "RUNNING"
	statusStaging      = "STAGING"
	statusStopped      = "STOPPED"
	statusStopping     = "STOPPING"
	statusTerminated   = "TERMINATED"
	statusUp           = "UP"

	operationTimeout = 60 // seconds

	// minDiskSize is the minimum/default size (in megabytes) for GCE
	// disks. GCE does not currently have a minimum disk size.
	minDiskSize int64 = 0
)

var (
	operationAttempts = utils.AttemptStrategy{
		Total: operationTimeout * time.Second,
		Delay: 10 * time.Second,
	}
)

type gceAuth struct {
	clientID    string
	clientEmail string
	privateKey  []byte
}

func (ga gceAuth) validate() error {
	if ga.clientID == "" {
		return &config.InvalidConfigValue{Key: osEnvClientID}
	}
	if ga.clientEmail == "" {
		return &config.InvalidConfigValue{Key: osEnvClientEmail}
	} else if _, err := mail.ParseAddress(ga.clientEmail); err != nil {
		err = errors.Trace(err)
		return &config.InvalidConfigValue{osEnvClientEmail, ga.clientEmail, err}
	}
	if len(ga.privateKey) == 0 {
		return &config.InvalidConfigValue{Key: osEnvPrivateKey}
	}
	return nil
}

func (ga gceAuth) newTransport() (*oauth.Transport, error) {
	token, err := newToken(ga, driverScopes)
	if err != nil {
		return nil, errors.Trace(err)
	}

	transport := oauth.Transport{
		Config: &oauth.Config{
			ClientId: ga.clientID,
			Scope:    driverScopes,
			TokenURL: tokenURL,
			AuthURL:  authURL,
		},
		Token: token,
	}
	return &transport, nil
}

var newToken = func(auth gceAuth, scopes string) (*oauth.Token, error) {
	jtok := jwt.NewToken(auth.clientEmail, scopes, auth.privateKey)
	jtok.ClaimSet.Aud = tokenURL

	token, err := jtok.Assert(&http.Client{})
	if err != nil {
		msg := "retrieving auth token for %s"
		return nil, errors.Annotatef(err, msg, auth.clientEmail)
	}
	return token, nil
}

func (ga *gceAuth) newConnection() (*compute.Service, error) {
	transport, err := ga.newTransport()
	if err != nil {
		return nil, errors.Trace(err)
	}
	service, err := newService(transport)
	return service, errors.Trace(err)
}

var newService = func(transport *oauth.Transport) (*compute.Service, error) {
	return compute.New(transport.Client())
}

type gceConnection struct {
	*compute.Service

	region    string
	projectID string
}

func (gce *gceConnection) validate() error {
	if gce.region == "" {
		return &config.InvalidConfigValue{Key: osEnvRegion}
	}
	if gce.projectID == "" {
		return &config.InvalidConfigValue{Key: osEnvProjectID}
	}
	return nil
}

func (gce *gceConnection) connect(auth gceAuth) error {
	if gce.Service != nil {
		return errors.New("connect() failed (already connected)")
	}

	service, err := auth.newConnection()
	if err != nil {
		return errors.Trace(err)
	}

	gce.Service = service
	return nil
}

func (gce *gceConnection) verifyCredentials() error {
	call := gce.Projects.Get(gce.projectID)
	if _, err := call.Do(); err != nil {
		return errors.Trace(err)
	}
	return nil
}

func (gce *gceConnection) waitOperation(operation *compute.Operation) error {
	opID := operation.ClientOperationId

	logger.Infof("GCE operation %q, waiting...", opID)
	for a := operationAttempts.Start(); a.Next(); {
		var err error
		if operation.Status == statusDone {
			break
		}
		call := gce.GlobalOperations.Get(gce.projectID, opID)
		operation, err = call.Do()
		if err != nil {
			return errors.Annotate(err, "waiting for operation to complete")
		}
	}
	if operation.Status != statusDone {
		msg := "timed out after %d seconds waiting for GCE operation to finish"
		return errors.Errorf(msg, operationTimeout)
	}
	if operation.Error != nil {
		for _, err := range operation.Error.Errors {
			logger.Errorf("GCE operation failed: (%s) %s", err.Code, err.Message)
		}
		return errors.Errorf("GCE operation %q failed", opID)
	}

	logger.Infof("GCE operation %q finished", opID)
	return nil
}

func (gce *gceConnection) instance(zone, id string) (*compute.Instance, error) {
	call := gce.Instances.Get(gce.projectID, zone, id)
	inst, err := call.Do()
	return inst, errors.Trace(err)
}

func (gce *gceConnection) addInstance(inst *compute.Instance, machineType string, zones []string) error {
	for _, zoneName := range zones {
		inst.MachineType = resolveMachineType(zoneName, machineType)
		call := gce.Instances.Insert(
			gce.projectID,
			zoneName,
			inst,
		)
		operation, err := call.Do()
		if err != nil {
			// We are guaranteed the insert failed at the point.
			return errors.Annotate(err, "sending new instance request")
		}
		waitErr := gce.waitOperation(operation)

		// Check if the instance was created.
		realized, err := gce.instance(zoneName, inst.Name)
		if err != nil {
			if waitErr == nil {
				return errors.Trace(err)
			}
			// Try the next zone.
			logger.Errorf("failed to get new instance in zone %q: %v", zoneName, waitErr)
			continue
		}

		// Success!
		*inst = *realized
		return nil
	}
	return errors.Errorf("not able to provision in any zone")
}

func (gce *gceConnection) instances(env environs.Environ) ([]*compute.Instance, error) {
	// env won't be nil.
	prefix := common.MachineFullName(env, "")

	call := gce.Instances.AggregatedList(gce.projectID)
	call = call.Filter("name eq " + prefix + ".*")

	var results []*compute.Instance
	for {
		raw, err := call.Do()
		if err != nil {
			return results, errors.Trace(err)
		}

		for _, item := range raw.Items {
			results = append(results, item.Instances...)
		}

		if raw.NextPageToken == "" {
			break
		}
		call = call.PageToken(raw.NextPageToken)
	}

	return results, nil
}

func (gce *gceConnection) availabilityZones(region string) ([]*compute.Zone, error) {
	call := gce.Zones.List(gce.projectID)
	if region != "" {
		call = call.Filter("name eq " + region + "-")
	}
	var results []*compute.Zone
	for {
		raw, err := call.Do()
		if err != nil {
			return nil, errors.Trace(err)
		}

		results = append(results, raw.Items...)

		if raw.NextPageToken == "" {
			break
		}
		call = call.PageToken(raw.NextPageToken)
	}

	return results, nil
}

func (gce *gceConnection) removeInstance(id, zone string) error {
	call := gce.Instances.Delete(gce.projectID, zone, id)
	operation, err := call.Do()
	if err != nil {
		return errors.Trace(err)
	}
	if err := gce.waitOperation(operation); err != nil {
		return errors.Trace(err)
	}

	// Clean up the instance's root disk.
	err = gce.removeDisk(id, zone)
	return errors.Trace(err)
}

func (gce *gceConnection) removeInstances(env environs.Environ, ids ...string) error {
	if len(ids) == 0 {
		return nil
	}

	instances, err := gce.instances(env)
	if err != nil {
		return errors.Annotatef(err, "while removing instances %v", ids)
	}

	var failed []string
	for _, instID := range ids {
		for _, inst := range instances {
			if inst.Name == instID {
				if err := gce.removeInstance(instID, inst.Zone); err != nil {
					failed = append(failed, instID)
					logger.Errorf("while removing instance %q: %v", instID, err)
				}
				break
			}
		}
	}
	if len(failed) != 0 {
		return errors.Errorf("some instance removals failed: %v", failed)
	}
	return nil
}

func (gce *gceConnection) removeDisk(id, zone string) error {
	call := gce.Disks.Delete(gce.projectID, zone, id)
	operation, err := call.Do()
	if err != nil {
		return errors.Trace(err)
	}
	err = gce.waitOperation(operation)
	return errors.Trace(err)
}

func (gce *gceConnection) firewall(name string) (*compute.Firewall, error) {
	call := gce.Firewalls.Get(gce.projectID, name)
	firewall, err := call.Do()
	if err != nil {
		return nil, errors.Annotate(err, "while getting firewall from GCE")
	}
	return firewall, nil
}

func (gce *gceConnection) setFirewall(name string, firewall *compute.Firewall) error {
	var err error
	var operation *compute.Operation
	if firewall == nil {
		call := gce.Firewalls.Delete(gce.projectID, name)
		operation, err = call.Do()
		if err != nil {
			return errors.Trace(err)
		}
	} else if name == "" {
		call := gce.Firewalls.Insert(gce.projectID, firewall)
		operation, err = call.Do()
		if err != nil {
			return errors.Trace(err)
		}
	} else {
		call := gce.Firewalls.Update(gce.projectID, name, firewall)
		operation, err = call.Do()
		if err != nil {
			return errors.Trace(err)
		}
	}
	if err := gce.waitOperation(operation); err != nil {
		return errors.Trace(err)
	}
	return nil
}

func filterInstances(instances []*compute.Instance, statuses ...string) []*compute.Instance {
	var results []*compute.Instance
	for _, inst := range instances {
		if !checkInstStatus(inst, statuses...) {
			continue
		}
		results = append(results, inst)
	}
	return results
}

func checkInstStatus(inst *compute.Instance, statuses ...string) bool {
	for _, status := range statuses {
		if inst.Status == status {
			return true
		}
	}
	return false
}

type diskSpec struct {
	// sizeHint is the requested disk size in Gigabytes.
	sizeHint int64
	imageURL string
	boot     bool
	scratch  bool
	readonly bool
}

func (ds *diskSpec) size() int64 {
	size := minDiskSize
	if ds.sizeHint >= minDiskSize {
		size = ds.sizeHint
	}
	return size
}

func (ds *diskSpec) newAttached() *compute.AttachedDisk {
	diskType := diskTypePersistent // The default.
	if ds.scratch {
		diskType = diskTypeScratch
	}
	mode := diskModeRW // The default.
	if ds.readonly {
		mode = diskModeRO
	}

	disk := compute.AttachedDisk{
		Type: diskType,
		Boot: ds.boot,
		Mode: mode,
		InitializeParams: &compute.AttachedDiskInitializeParams{
			// DiskName (defaults to instance name)
			DiskSizeGb: ds.size(),
			// DiskType (defaults to pd-standard, pd-ssd, local-ssd)
			SourceImage: ds.imageURL,
		},
		// Interface (defaults to SCSI)
		// DeviceName (GCE sets this, persistent disk only)
	}
	return &disk
}

// firewallSpec expands a port range set in to compute.FirewallAllowed
// and returns a compute.Firewall for the provided name.
func firewallSpec(name string, ps network.PortSet) *compute.Firewall {
	firewall := compute.Firewall{
		// Allowed is set below.
		// Description is not set.
		Name: name,
		// Network: (defaults to global)
		// SourceRanges is not set.
		// SourceTags is not set.
		// TargetTags is not set.
	}

	for _, protocol := range ps.Protocols() {
		allowed := compute.FirewallAllowed{
			IPProtocol: protocol,
			Ports:      ps.PortStrings(protocol),
		}
		firewall.Allowed = append(firewall.Allowed, &allowed)
	}
	return &firewall
}

func packMetadata(data map[string]string) *compute.Metadata {
	var items []*compute.MetadataItems
	for key, value := range data {
		item := compute.MetadataItems{
			Key:   key,
			Value: value,
		}
		items = append(items, &item)
	}
	return &compute.Metadata{Items: items}
}

func unpackMetadata(data *compute.Metadata) map[string]string {
	if data == nil {
		return nil
	}

	var result map[string]string
	for _, item := range data.Items {
		result[item.Key] = item.Value
	}
	return result
}
<commit_msg>provider/gce: Add a TODO about timeouts.<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package gce

import (
	"net/http"
	"net/mail"
	"time"

	"code.google.com/p/goauth2/oauth"
	"code.google.com/p/goauth2/oauth/jwt"
	"code.google.com/p/google-api-go-client/compute/v1"
	"github.com/juju/errors"
	"github.com/juju/utils"

	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/network"
	"github.com/juju/juju/provider/common"
)

const (
	driverScopes = "https://www.googleapis.com/auth/compute " +
		"https://www.googleapis.com/auth/devstorage.full_control"

	tokenURL = "https://accounts.google.com/o/oauth2/token"

	authURL = "https://accounts.google.com/o/oauth2/auth"

	partialMachineType = "zones/%s/machineTypes/%s"

	diskTypeScratch    = "SCRATCH"
	diskTypePersistent = "PERSISTENT"
	diskModeRW         = "READ_WRITE"
	diskModeRO         = "READ_ONLY"

	statusDone         = "DONE"
	statusDown         = "DOWN"
	statusPending      = "PENDING"
	statusProvisioning = "PROVISIONING"
	statusRunning      = "RUNNING"
	statusStaging      = "STAGING"
	statusStopped      = "STOPPED"
	statusStopping     = "STOPPING"
	statusTerminated   = "TERMINATED"
	statusUp           = "UP"

	operationTimeout = 60 // seconds

	// minDiskSize is the minimum/default size (in megabytes) for GCE
	// disks. GCE does not currently have a minimum disk size.
	minDiskSize int64 = 0
)

var (
	operationAttempts = utils.AttemptStrategy{
		Total: operationTimeout * time.Second,
		Delay: 10 * time.Second,
	}
)

type gceAuth struct {
	clientID    string
	clientEmail string
	privateKey  []byte
}

func (ga gceAuth) validate() error {
	if ga.clientID == "" {
		return &config.InvalidConfigValue{Key: osEnvClientID}
	}
	if ga.clientEmail == "" {
		return &config.InvalidConfigValue{Key: osEnvClientEmail}
	} else if _, err := mail.ParseAddress(ga.clientEmail); err != nil {
		err = errors.Trace(err)
		return &config.InvalidConfigValue{osEnvClientEmail, ga.clientEmail, err}
	}
	if len(ga.privateKey) == 0 {
		return &config.InvalidConfigValue{Key: osEnvPrivateKey}
	}
	return nil
}

func (ga gceAuth) newTransport() (*oauth.Transport, error) {
	token, err := newToken(ga, driverScopes)
	if err != nil {
		return nil, errors.Trace(err)
	}

	transport := oauth.Transport{
		Config: &oauth.Config{
			ClientId: ga.clientID,
			Scope:    driverScopes,
			TokenURL: tokenURL,
			AuthURL:  authURL,
		},
		Token: token,
	}
	return &transport, nil
}

var newToken = func(auth gceAuth, scopes string) (*oauth.Token, error) {
	jtok := jwt.NewToken(auth.clientEmail, scopes, auth.privateKey)
	jtok.ClaimSet.Aud = tokenURL

	token, err := jtok.Assert(&http.Client{})
	if err != nil {
		msg := "retrieving auth token for %s"
		return nil, errors.Annotatef(err, msg, auth.clientEmail)
	}
	return token, nil
}

func (ga *gceAuth) newConnection() (*compute.Service, error) {
	transport, err := ga.newTransport()
	if err != nil {
		return nil, errors.Trace(err)
	}
	service, err := newService(transport)
	return service, errors.Trace(err)
}

var newService = func(transport *oauth.Transport) (*compute.Service, error) {
	return compute.New(transport.Client())
}

type gceConnection struct {
	*compute.Service

	region    string
	projectID string
}

func (gce *gceConnection) validate() error {
	if gce.region == "" {
		return &config.InvalidConfigValue{Key: osEnvRegion}
	}
	if gce.projectID == "" {
		return &config.InvalidConfigValue{Key: osEnvProjectID}
	}
	return nil
}

func (gce *gceConnection) connect(auth gceAuth) error {
	if gce.Service != nil {
		return errors.New("connect() failed (already connected)")
	}

	service, err := auth.newConnection()
	if err != nil {
		return errors.Trace(err)
	}

	gce.Service = service
	return nil
}

func (gce *gceConnection) verifyCredentials() error {
	call := gce.Projects.Get(gce.projectID)
	if _, err := call.Do(); err != nil {
		return errors.Trace(err)
	}
	return nil
}

func (gce *gceConnection) waitOperation(operation *compute.Operation) error {
	opID := operation.ClientOperationId

	logger.Infof("GCE operation %q, waiting...", opID)
	for a := operationAttempts.Start(); a.Next(); {
		var err error
		if operation.Status == statusDone {
			break
		}
		call := gce.GlobalOperations.Get(gce.projectID, opID)
		operation, err = call.Do()
		if err != nil {
			return errors.Annotate(err, "waiting for operation to complete")
		}
	}
	if operation.Status != statusDone {
		msg := "timed out after %d seconds waiting for GCE operation to finish"
		return errors.Errorf(msg, operationTimeout)
	}
	if operation.Error != nil {
		for _, err := range operation.Error.Errors {
			logger.Errorf("GCE operation failed: (%s) %s", err.Code, err.Message)
		}
		return errors.Errorf("GCE operation %q failed", opID)
	}

	logger.Infof("GCE operation %q finished", opID)
	return nil
}

func (gce *gceConnection) instance(zone, id string) (*compute.Instance, error) {
	call := gce.Instances.Get(gce.projectID, zone, id)
	inst, err := call.Do()
	return inst, errors.Trace(err)
}

func (gce *gceConnection) addInstance(inst *compute.Instance, machineType string, zones []string) error {
	for _, zoneName := range zones {
		inst.MachineType = resolveMachineType(zoneName, machineType)
		call := gce.Instances.Insert(
			gce.projectID,
			zoneName,
			inst,
		)
		operation, err := call.Do()
		if err != nil {
			// We are guaranteed the insert failed at the point.
			return errors.Annotate(err, "sending new instance request")
		}
		waitErr := gce.waitOperation(operation)

		// Check if the instance was created.
		realized, err := gce.instance(zoneName, inst.Name)
		if err != nil {
			if waitErr == nil {
				return errors.Trace(err)
			}
			// Try the next zone.
			logger.Errorf("failed to get new instance in zone %q: %v", zoneName, waitErr)
			continue
		}

		// Success!
		*inst = *realized
		return nil
	}
	return errors.Errorf("not able to provision in any zone")
}

func (gce *gceConnection) instances(env environs.Environ) ([]*compute.Instance, error) {
	// env won't be nil.
	prefix := common.MachineFullName(env, "")

	call := gce.Instances.AggregatedList(gce.projectID)
	call = call.Filter("name eq " + prefix + ".*")

	// TODO(ericsnow) Add a timeout?
	var results []*compute.Instance
	for {
		raw, err := call.Do()
		if err != nil {
			return results, errors.Trace(err)
		}

		for _, item := range raw.Items {
			results = append(results, item.Instances...)
		}

		if raw.NextPageToken == "" {
			break
		}
		call = call.PageToken(raw.NextPageToken)
	}

	return results, nil
}

func (gce *gceConnection) availabilityZones(region string) ([]*compute.Zone, error) {
	call := gce.Zones.List(gce.projectID)
	if region != "" {
		call = call.Filter("name eq " + region + "-")
	}
	// TODO(ericsnow) Add a timeout?
	var results []*compute.Zone
	for {
		raw, err := call.Do()
		if err != nil {
			return nil, errors.Trace(err)
		}

		results = append(results, raw.Items...)

		if raw.NextPageToken == "" {
			break
		}
		call = call.PageToken(raw.NextPageToken)
	}

	return results, nil
}

func (gce *gceConnection) removeInstance(id, zone string) error {
	call := gce.Instances.Delete(gce.projectID, zone, id)
	operation, err := call.Do()
	if err != nil {
		return errors.Trace(err)
	}
	if err := gce.waitOperation(operation); err != nil {
		return errors.Trace(err)
	}

	// Clean up the instance's root disk.
	err = gce.removeDisk(id, zone)
	return errors.Trace(err)
}

func (gce *gceConnection) removeInstances(env environs.Environ, ids ...string) error {
	if len(ids) == 0 {
		return nil
	}

	instances, err := gce.instances(env)
	if err != nil {
		return errors.Annotatef(err, "while removing instances %v", ids)
	}

	var failed []string
	for _, instID := range ids {
		for _, inst := range instances {
			if inst.Name == instID {
				if err := gce.removeInstance(instID, inst.Zone); err != nil {
					failed = append(failed, instID)
					logger.Errorf("while removing instance %q: %v", instID, err)
				}
				break
			}
		}
	}
	if len(failed) != 0 {
		return errors.Errorf("some instance removals failed: %v", failed)
	}
	return nil
}

func (gce *gceConnection) removeDisk(id, zone string) error {
	call := gce.Disks.Delete(gce.projectID, zone, id)
	operation, err := call.Do()
	if err != nil {
		return errors.Trace(err)
	}
	err = gce.waitOperation(operation)
	return errors.Trace(err)
}

func (gce *gceConnection) firewall(name string) (*compute.Firewall, error) {
	call := gce.Firewalls.Get(gce.projectID, name)
	firewall, err := call.Do()
	if err != nil {
		return nil, errors.Annotate(err, "while getting firewall from GCE")
	}
	return firewall, nil
}

func (gce *gceConnection) setFirewall(name string, firewall *compute.Firewall) error {
	var err error
	var operation *compute.Operation
	if firewall == nil {
		call := gce.Firewalls.Delete(gce.projectID, name)
		operation, err = call.Do()
		if err != nil {
			return errors.Trace(err)
		}
	} else if name == "" {
		call := gce.Firewalls.Insert(gce.projectID, firewall)
		operation, err = call.Do()
		if err != nil {
			return errors.Trace(err)
		}
	} else {
		call := gce.Firewalls.Update(gce.projectID, name, firewall)
		operation, err = call.Do()
		if err != nil {
			return errors.Trace(err)
		}
	}
	if err := gce.waitOperation(operation); err != nil {
		return errors.Trace(err)
	}
	return nil
}

func filterInstances(instances []*compute.Instance, statuses ...string) []*compute.Instance {
	var results []*compute.Instance
	for _, inst := range instances {
		if !checkInstStatus(inst, statuses...) {
			continue
		}
		results = append(results, inst)
	}
	return results
}

func checkInstStatus(inst *compute.Instance, statuses ...string) bool {
	for _, status := range statuses {
		if inst.Status == status {
			return true
		}
	}
	return false
}

type diskSpec struct {
	// sizeHint is the requested disk size in Gigabytes.
	sizeHint int64
	imageURL string
	boot     bool
	scratch  bool
	readonly bool
}

func (ds *diskSpec) size() int64 {
	size := minDiskSize
	if ds.sizeHint >= minDiskSize {
		size = ds.sizeHint
	}
	return size
}

func (ds *diskSpec) newAttached() *compute.AttachedDisk {
	diskType := diskTypePersistent // The default.
	if ds.scratch {
		diskType = diskTypeScratch
	}
	mode := diskModeRW // The default.
	if ds.readonly {
		mode = diskModeRO
	}

	disk := compute.AttachedDisk{
		Type: diskType,
		Boot: ds.boot,
		Mode: mode,
		InitializeParams: &compute.AttachedDiskInitializeParams{
			// DiskName (defaults to instance name)
			DiskSizeGb: ds.size(),
			// DiskType (defaults to pd-standard, pd-ssd, local-ssd)
			SourceImage: ds.imageURL,
		},
		// Interface (defaults to SCSI)
		// DeviceName (GCE sets this, persistent disk only)
	}
	return &disk
}

// firewallSpec expands a port range set in to compute.FirewallAllowed
// and returns a compute.Firewall for the provided name.
func firewallSpec(name string, ps network.PortSet) *compute.Firewall {
	firewall := compute.Firewall{
		// Allowed is set below.
		// Description is not set.
		Name: name,
		// Network: (defaults to global)
		// SourceRanges is not set.
		// SourceTags is not set.
		// TargetTags is not set.
	}

	for _, protocol := range ps.Protocols() {
		allowed := compute.FirewallAllowed{
			IPProtocol: protocol,
			Ports:      ps.PortStrings(protocol),
		}
		firewall.Allowed = append(firewall.Allowed, &allowed)
	}
	return &firewall
}

func packMetadata(data map[string]string) *compute.Metadata {
	var items []*compute.MetadataItems
	for key, value := range data {
		item := compute.MetadataItems{
			Key:   key,
			Value: value,
		}
		items = append(items, &item)
	}
	return &compute.Metadata{Items: items}
}

func unpackMetadata(data *compute.Metadata) map[string]string {
	if data == nil {
		return nil
	}

	var result map[string]string
	for _, item := range data.Items {
		result[item.Key] = item.Value
	}
	return result
}
<|endoftext|>


<commit_before>package postgis

import (
	"fmt"
	"github.com/aodin/aspect"
	_ "github.com/aodin/aspect/postgres"
)

// Importing PostGIS implies you'll be using PostGres

type LatLong struct {
	Latitude, Longitude float64
}

// A point with the implied SRID of 4326
// TODO parameterization
func (p LatLong) Compile(d aspect.Dialect, params *aspect.Parameters) (string, error) {
	return fmt.Sprintf(
		`ST_SetSRID(ST_Point(%f, %f), 4326)::geography`,
		p.Longitude,
		p.Latitude,
	), nil
}

func (p LatLong) Create(d aspect.Dialect) (string, error) {
	return "POINT", nil
}

// TODO Shapes implement both the Compiles interface and dbType (which
// is not exported but probably should be)
type Shape interface {
	aspect.Compiles
	Create(aspect.Dialect) (string, error)
}

type Point struct {
	X, Y float64
}

func (p Point) String() string {
	return fmt.Sprintf(`POINT(%f %f)`, p.X, p.Y)
}

// TODO parameterization
func (p Point) Compile(d aspect.Dialect, params *aspect.Parameters) (string, error) {
	return fmt.Sprintf(`ST_Point(%f, %f)`, p.X, p.Y), nil
}

func (p Point) Create(d aspect.Dialect) (string, error) {
	return "POINT", nil
}

type MultiPoint struct {
	Points []Point
}

// TODO
func (p MultiPoint) Compile(d aspect.Dialect, params *aspect.Parameters) (string, error) {
	return "", nil
}

func (p MultiPoint) Create(d aspect.Dialect) (string, error) {
	return "MULTIPOINT", nil
}

type Linestring struct {
	Points []Point
}

func (p Linestring) Compile(d aspect.Dialect, params *aspect.Parameters) (string, error) {
	return "", nil
}

func (p Linestring) Create(d aspect.Dialect) (string, error) {
	return "LINESTRING", nil
}

type Polygon struct {
	Exterior  Linestring
	Interiors []Linestring
}

func (p Polygon) Compile(d aspect.Dialect, params *aspect.Parameters) (string, error) {
	return "", nil
}

func (p Polygon) Create(d aspect.Dialect) (string, error) {
	return "POLYGON", nil
}
<commit_msg>postgis elements should implement the aspect.Compiles interface<commit_after>package postgis

import (
	"fmt"
	"github.com/aodin/aspect"
	"github.com/aodin/aspect/postgres"
)

// Importing PostGIS implies you'll be using PostGres

type LatLong struct {
	Latitude, Longitude float64
}

// String returns the element's SQL using the default dialect.
func (p LatLong) String() string {
	compiled, _ := p.Compile(&postgres.PostGres{}, aspect.Params())
	return compiled
}

// A point with the implied SRID of 4326
// TODO parameterization
func (p LatLong) Compile(d aspect.Dialect, params *aspect.Parameters) (string, error) {
	return fmt.Sprintf(
		`ST_SetSRID(ST_Point(%f, %f), 4326)::geography`,
		p.Longitude,
		p.Latitude,
	), nil
}

func (p LatLong) Create(d aspect.Dialect) (string, error) {
	return "POINT", nil
}

// TODO Shapes implement both the Compiles interface and dbType (which
// is not exported but probably should be)
type Shape interface {
	aspect.Compiles
	Create(aspect.Dialect) (string, error)
}

type Point struct {
	X, Y float64
}

func (p Point) String() string {
	return fmt.Sprintf(`POINT(%f %f)`, p.X, p.Y)
}

// TODO parameterization
func (p Point) Compile(d aspect.Dialect, params *aspect.Parameters) (string, error) {
	return fmt.Sprintf(`ST_Point(%f, %f)`, p.X, p.Y), nil
}

func (p Point) Create(d aspect.Dialect) (string, error) {
	return "POINT", nil
}

type MultiPoint struct {
	Points []Point
}

// String returns the element's SQL using the default dialect.
func (p MultiPoint) String() string {
	compiled, _ := p.Compile(&postgres.PostGres{}, aspect.Params())
	return compiled
}

// TODO
func (p MultiPoint) Compile(d aspect.Dialect, params *aspect.Parameters) (string, error) {
	return "", nil
}

func (p MultiPoint) Create(d aspect.Dialect) (string, error) {
	return "MULTIPOINT", nil
}

type Linestring struct {
	Points []Point
}

// String returns the element's SQL using the default dialect.
func (p Linestring) String() string {
	compiled, _ := p.Compile(&postgres.PostGres{}, aspect.Params())
	return compiled
}

func (p Linestring) Compile(d aspect.Dialect, params *aspect.Parameters) (string, error) {
	return "", nil
}

func (p Linestring) Create(d aspect.Dialect) (string, error) {
	return "LINESTRING", nil
}

type Polygon struct {
	Exterior  Linestring
	Interiors []Linestring
}

// String returns the element's SQL using the default dialect.
func (p Polygon) String() string {
	compiled, _ := p.Compile(&postgres.PostGres{}, aspect.Params())
	return compiled
}

func (p Polygon) Compile(d aspect.Dialect, params *aspect.Parameters) (string, error) {
	return "", nil
}

func (p Polygon) Create(d aspect.Dialect) (string, error) {
	return "POLYGON", nil
}
<|endoftext|>


<commit_before>package power

import (
	"path"
	"testing"

	"github.com/ready-steady/simulation/system"
	"github.com/ready-steady/simulation/time"
	"github.com/ready-steady/support/assert"
)

const (
	fixturePath = "fixtures"
)

func TestCompute(t *testing.T) {
	platform, application, _ := system.Load(findFixture("002_040.tgff"))

	profile := system.NewProfile(platform, application)
	list := time.NewList(platform, application)
	schedule := list.Compute(profile.Mobility)

	power, _ := New(platform, application, 1e-3)

	P := make([]float64, 2*440)
	power.Compute(schedule, P, 440)
	assert.Equal(P, fixturePData, t)

	P = make([]float64, 2*42)
	power.Compute(schedule, P, 42)
	assert.Equal(P, fixturePData[:2*42], t)
}

func findFixture(name string) string {
	return path.Join(fixturePath, name)
}
<commit_msg>Added a benchmark for power<commit_after>package power

import (
	"path"
	"testing"

	"github.com/ready-steady/simulation/system"
	"github.com/ready-steady/simulation/time"
	"github.com/ready-steady/support/assert"
)

const (
	fixturePath = "fixtures"
)

func TestCompute(t *testing.T) {
	platform, application, _ := system.Load(findFixture("002_040.tgff"))
	profile := system.NewProfile(platform, application)
	list := time.NewList(platform, application)
	schedule := list.Compute(profile.Mobility)
	power, _ := New(platform, application, 1e-3)

	P := make([]float64, 2*440)
	power.Compute(schedule, P, 440)
	assert.Equal(P, fixturePData, t)

	P = make([]float64, 2*42)
	power.Compute(schedule, P, 42)
	assert.Equal(P, fixturePData[:2*42], t)
}

func BenchmarkCompute(b *testing.B) {
	const (
		Δt = 1e-5
	)

	platform, application, _ := system.Load(findFixture("002_040.tgff"))
	profile := system.NewProfile(platform, application)
	list := time.NewList(platform, application)
	schedule := list.Compute(profile.Mobility)
	power, _ := New(platform, application, Δt)

	sc := uint32(schedule.Span / Δt)
	P := make([]float64, 2*sc)

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		power.Compute(schedule, P, sc)
	}
}

func findFixture(name string) string {
	return path.Join(fixturePath, name)
}
<|endoftext|>


<commit_before>package pathfs_frontend

import (
	"os"
	"path/filepath"
	"time"
	"fmt"

	"github.com/hanwen/go-fuse/fuse"
	"github.com/hanwen/go-fuse/fuse/nodefs"
	"github.com/hanwen/go-fuse/fuse/pathfs"
	"github.com/rfjakob/gocryptfs/cryptfs"
)

type FS struct {
	*cryptfs.CryptFS
	pathfs.FileSystem    // loopbackFileSystem
	backing string       // Backing directory
}

// Encrypted FUSE overlay filesystem
func NewFS(key []byte, backing string, useOpenssl bool) *FS {
	return &FS{
		CryptFS:     cryptfs.NewCryptFS(key, useOpenssl),
		FileSystem:  pathfs.NewLoopbackFileSystem(backing),
		backing:     backing,

	}
}

// GetPath - get the absolute path of the backing file
func (fs *FS) GetPath(relPath string) string {
	return filepath.Join(fs.backing, fs.EncryptPath(relPath))
}

func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
	cryptfs.Debug.Printf("FS.GetAttr('%s')\n", name)
	cName := fs.EncryptPath(name)
	a, status := fs.FileSystem.GetAttr(cName, context)
	if a == nil {
		cryptfs.Debug.Printf("FS.GetAttr failed: %s\n", status.String())
		return a, status
	}
	if a.IsRegular() {
		a.Size = fs.PlainSize(a.Size)
	} else if a.IsSymlink() {
		target, _ := fs.Readlink(name, context)
		a.Size = uint64(len(target))
	}
	return a, status
}

func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
	cryptfs.Debug.Printf("OpenDir(%s)\n", dirName)
	cipherEntries, status := fs.FileSystem.OpenDir(fs.EncryptPath(dirName), context);
	var plain []fuse.DirEntry
	if cipherEntries != nil {
		for i := range cipherEntries {
			cName := cipherEntries[i].Name
			name, err := fs.DecryptPath(cName)
			if err != nil {
				if dirName == "" && cName == cryptfs.ConfDefaultName {
					// Silently ignore "gocryptfs.conf" in the top level dir
					continue
				}
				fmt.Printf("Invalid name \"%s\" in dir \"%s\": %s\n", cName, name, err)
				continue
			}
			cipherEntries[i].Name = name
			plain = append(plain, cipherEntries[i])
		}
	}
	return plain, status
}

// We always need read access to do read-modify-write cycles
func (fs *FS) mangleOpenFlags(flags uint32) (newFlags int, writeOnly bool) {
	newFlags = int(flags)
	if newFlags & os.O_WRONLY > 0 {
		writeOnly = true
		newFlags = newFlags ^ os.O_WRONLY | os.O_RDWR
	}
	// We also cannot open the file in append mode, we need to seek back for RMW
	newFlags = newFlags &^ os.O_APPEND

	return newFlags, writeOnly
}

func (fs *FS) Open(name string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) {
	cryptfs.Debug.Printf("Open(%s)\n", name)

	iflags, writeOnly := fs.mangleOpenFlags(flags)
	f, err := os.OpenFile(fs.GetPath(name), iflags, 0666)
	if err != nil {
		return nil, fuse.ToStatus(err)
	}

	return NewFile(f, writeOnly, fs.CryptFS), fuse.OK
}

func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Context) (fuseFile nodefs.File, code fuse.Status) {
	iflags, writeOnly := fs.mangleOpenFlags(flags)
	f, err := os.OpenFile(fs.GetPath(path), iflags|os.O_CREATE, os.FileMode(mode))
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	return NewFile(f, writeOnly, fs.CryptFS), fuse.OK
}

func (fs *FS) Chmod(path string, mode uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Chmod(fs.EncryptPath(path), mode, context)
}

func (fs *FS) Chown(path string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Chmod(fs.EncryptPath(path), gid, context)
}

func (fs *FS) Truncate(path string, offset uint64, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Truncate(fs.EncryptPath(path), offset, context)
}

func (fs *FS) Utimens(path string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Utimens(fs.EncryptPath(path), Atime, Mtime, context)
}

func (fs *FS) Readlink(name string, context *fuse.Context) (out string, status fuse.Status) {
	dst, status := fs.FileSystem.Readlink(fs.EncryptPath(name), context)
	if status != fuse.OK {
		return "", status
	}
	dstPlain, err := fs.DecryptPath(dst)
	if err != nil {
		cryptfs.Warn.Printf("Failed decrypting symlink: %s\n", err.Error())
		return "", fuse.EIO
	}
	return dstPlain, status
}

func (fs *FS) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Mknod(fs.EncryptPath(name), mode, dev, context)
}

func (fs *FS) Mkdir(path string, mode uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Mkdir(fs.EncryptPath(path), mode, context)
}

func (fs *FS) Unlink(name string, context *fuse.Context) (code fuse.Status) {
	cName := fs.EncryptPath(name)
	code = fs.FileSystem.Unlink(cName, context)
	if code != fuse.OK {
		cryptfs.Notice.Printf("Unlink failed on %s [%s], code=%s\n", name, cName, code.String())
	}
	return code
}

func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Rmdir(fs.EncryptPath(name), context)
}

func (fs *FS) Symlink(pointedTo string, linkName string, context *fuse.Context) (code fuse.Status) {
	// TODO symlink encryption
	cryptfs.Debug.Printf("Symlink(\"%s\", \"%s\")\n", pointedTo, linkName)
	return fs.FileSystem.Symlink(fs.EncryptPath(pointedTo), fs.EncryptPath(linkName), context)
}

func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (codee fuse.Status) {
	return fs.FileSystem.Rename(fs.EncryptPath(oldPath), fs.EncryptPath(newPath), context)
}

func (fs *FS) Link(orig string, newName string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Link(fs.EncryptPath(orig), fs.EncryptPath(newName), context)
}

func (fs *FS) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Access(fs.EncryptPath(name), mode, context)
}

func (fs *FS) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
	return nil, fuse.ENOSYS
}

func (fs *FS) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
	return fuse.ENOSYS
}

func (fs *FS) ListXAttr(name string, context *fuse.Context) ([]string, fuse.Status) {
	return nil, fuse.ENOSYS
}

func (fs *FS) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status {
	return fuse.ENOSYS
}
<commit_msg>Fix Chown parameter order<commit_after>package pathfs_frontend

import (
	"os"
	"path/filepath"
	"time"
	"fmt"

	"github.com/hanwen/go-fuse/fuse"
	"github.com/hanwen/go-fuse/fuse/nodefs"
	"github.com/hanwen/go-fuse/fuse/pathfs"
	"github.com/rfjakob/gocryptfs/cryptfs"
)

type FS struct {
	*cryptfs.CryptFS
	pathfs.FileSystem    // loopbackFileSystem
	backing string       // Backing directory
}

// Encrypted FUSE overlay filesystem
func NewFS(key []byte, backing string, useOpenssl bool) *FS {
	return &FS{
		CryptFS:     cryptfs.NewCryptFS(key, useOpenssl),
		FileSystem:  pathfs.NewLoopbackFileSystem(backing),
		backing:     backing,

	}
}

// GetPath - get the absolute path of the backing file
func (fs *FS) GetPath(relPath string) string {
	return filepath.Join(fs.backing, fs.EncryptPath(relPath))
}

func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
	cryptfs.Debug.Printf("FS.GetAttr('%s')\n", name)
	cName := fs.EncryptPath(name)
	a, status := fs.FileSystem.GetAttr(cName, context)
	if a == nil {
		cryptfs.Debug.Printf("FS.GetAttr failed: %s\n", status.String())
		return a, status
	}
	if a.IsRegular() {
		a.Size = fs.PlainSize(a.Size)
	} else if a.IsSymlink() {
		target, _ := fs.Readlink(name, context)
		a.Size = uint64(len(target))
	}
	return a, status
}

func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
	cryptfs.Debug.Printf("OpenDir(%s)\n", dirName)
	cipherEntries, status := fs.FileSystem.OpenDir(fs.EncryptPath(dirName), context);
	var plain []fuse.DirEntry
	if cipherEntries != nil {
		for i := range cipherEntries {
			cName := cipherEntries[i].Name
			name, err := fs.DecryptPath(cName)
			if err != nil {
				if dirName == "" && cName == cryptfs.ConfDefaultName {
					// Silently ignore "gocryptfs.conf" in the top level dir
					continue
				}
				fmt.Printf("Invalid name \"%s\" in dir \"%s\": %s\n", cName, name, err)
				continue
			}
			cipherEntries[i].Name = name
			plain = append(plain, cipherEntries[i])
		}
	}
	return plain, status
}

// We always need read access to do read-modify-write cycles
func (fs *FS) mangleOpenFlags(flags uint32) (newFlags int, writeOnly bool) {
	newFlags = int(flags)
	if newFlags & os.O_WRONLY > 0 {
		writeOnly = true
		newFlags = newFlags ^ os.O_WRONLY | os.O_RDWR
	}
	// We also cannot open the file in append mode, we need to seek back for RMW
	newFlags = newFlags &^ os.O_APPEND

	return newFlags, writeOnly
}

func (fs *FS) Open(name string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) {
	cryptfs.Debug.Printf("Open(%s)\n", name)

	iflags, writeOnly := fs.mangleOpenFlags(flags)
	f, err := os.OpenFile(fs.GetPath(name), iflags, 0666)
	if err != nil {
		return nil, fuse.ToStatus(err)
	}

	return NewFile(f, writeOnly, fs.CryptFS), fuse.OK
}

func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Context) (fuseFile nodefs.File, code fuse.Status) {
	iflags, writeOnly := fs.mangleOpenFlags(flags)
	f, err := os.OpenFile(fs.GetPath(path), iflags|os.O_CREATE, os.FileMode(mode))
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	return NewFile(f, writeOnly, fs.CryptFS), fuse.OK
}

func (fs *FS) Chmod(path string, mode uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Chmod(fs.EncryptPath(path), mode, context)
}

func (fs *FS) Chown(path string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Chown(fs.EncryptPath(path), uid, gid, context)
}

func (fs *FS) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Mknod(fs.EncryptPath(name), mode, dev, context)
}

func (fs *FS) Truncate(path string, offset uint64, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Truncate(fs.EncryptPath(path), offset, context)
}

func (fs *FS) Utimens(path string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Utimens(fs.EncryptPath(path), Atime, Mtime, context)
}

func (fs *FS) Readlink(name string, context *fuse.Context) (out string, status fuse.Status) {
	dst, status := fs.FileSystem.Readlink(fs.EncryptPath(name), context)
	if status != fuse.OK {
		return "", status
	}
	dstPlain, err := fs.DecryptPath(dst)
	if err != nil {
		cryptfs.Warn.Printf("Failed decrypting symlink: %s\n", err.Error())
		return "", fuse.EIO
	}
	return dstPlain, status
}

func (fs *FS) Mkdir(path string, mode uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Mkdir(fs.EncryptPath(path), mode, context)
}

func (fs *FS) Unlink(name string, context *fuse.Context) (code fuse.Status) {
	cName := fs.EncryptPath(name)
	code = fs.FileSystem.Unlink(cName, context)
	if code != fuse.OK {
		cryptfs.Notice.Printf("Unlink failed on %s [%s], code=%s\n", name, cName, code.String())
	}
	return code
}

func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Rmdir(fs.EncryptPath(name), context)
}

func (fs *FS) Symlink(pointedTo string, linkName string, context *fuse.Context) (code fuse.Status) {
	// TODO symlink encryption
	cryptfs.Debug.Printf("Symlink(\"%s\", \"%s\")\n", pointedTo, linkName)
	return fs.FileSystem.Symlink(fs.EncryptPath(pointedTo), fs.EncryptPath(linkName), context)
}

func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (codee fuse.Status) {
	return fs.FileSystem.Rename(fs.EncryptPath(oldPath), fs.EncryptPath(newPath), context)
}

func (fs *FS) Link(orig string, newName string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Link(fs.EncryptPath(orig), fs.EncryptPath(newName), context)
}

func (fs *FS) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Access(fs.EncryptPath(name), mode, context)
}

func (fs *FS) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
	return nil, fuse.ENOSYS
}

func (fs *FS) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
	return fuse.ENOSYS
}

func (fs *FS) ListXAttr(name string, context *fuse.Context) ([]string, fuse.Status) {
	return nil, fuse.ENOSYS
}

func (fs *FS) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status {
	return fuse.ENOSYS
}
<|endoftext|>