<commit_before>// Copyright 2016-2017 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"encoding/json"
	"io"
	"os"
	stdpath "path"
	"strings"
	"sync"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/logger"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/kbfs/kbfscrypto"
)

// SimpleFS is the simple filesystem rpc layer implementation.
type SimpleFS struct {
	lock       sync.RWMutex
	config     Config
	handles    map[keybase1.OpID]*handle
	inProgress map[keybase1.OpID]*inprogress
	log        logger.Logger
}

type inprogress struct {
	desc keybase1.OpDescription
	done chan error
}

type handle struct {
	node  Node
	async interface{}
	path  keybase1.Path
}

// make sure the interface is implemented
var _ keybase1.SimpleFSInterface = (*SimpleFS)(nil)

func newSimpleFS(config Config) *SimpleFS {
	log := config.MakeLogger("simplefs")
	return &SimpleFS{
		config:     config,
		handles:    map[keybase1.OpID]*handle{},
		inProgress: map[keybase1.OpID]*inprogress{},
		log:        log,
	}
}

// SimpleFSList - Begin list of items in directory at path
// Retrieve results with readList()
// Cannot be a single file to get flags/status,
// must be a directory.
func (k *SimpleFS) SimpleFSList(_ context.Context, arg keybase1.SimpleFSListArg) error {
	return k.startAsync(arg.OpID, keybase1.NewOpDescriptionWithList(
		keybase1.ListArgs{
			OpID: arg.OpID, Path: arg.Path,
		}), func(ctx context.Context) (err error) {

		node, ei, err := k.getRemoteNode(ctx, arg.Path)
		if err != nil {
			return err
		}
		var children map[string]EntryInfo
		switch ei.Type {
		case Dir:
			children, err = k.config.KBFSOps().GetDirChildren(ctx, node)
		default:
			children = map[string]EntryInfo{stdpath.Base(arg.Path.Kbfs()): ei}
		}
		if err != nil {
			return err
		}
		var des = make([]keybase1.Dirent, len(children))
		var i = 0
		for name, ei := range children {
			setStat(&des[i], &ei)
			des[i].Name = name
			i++
		}

		k.setResult(arg.OpID, keybase1.SimpleFSListResult{Entries: des})
		return nil
	})
}

// SimpleFSListRecursive - Begin recursive list of items in directory at path
func (k *SimpleFS) SimpleFSListRecursive(ctx context.Context, arg keybase1.SimpleFSListRecursiveArg) error {
	return k.startAsync(arg.OpID, keybase1.NewOpDescriptionWithListRecursive(
		keybase1.ListArgs{
			OpID: arg.OpID, Path: arg.Path,
		}), func(ctx context.Context) (err error) {

		// A stack of paths to process - ordering does not matter.
		// Here we don't walk symlinks, so no loops possible.
		var paths = []keybase1.Path{arg.Path}
		var des []keybase1.Dirent
		for len(paths) > 0 {
			// Take last element and shorten
			path := paths[len(paths)-1]
			paths = paths[:len(paths)-1]
			node, _, err := k.getRemoteNode(ctx, path)<commit_msg>simplefs: Favorite listing for client<commit_after>// Copyright 2016-2017 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"encoding/json"
	"io"
	"os"
	stdpath "path"
	"strings"
	"sync"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/logger"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/kbfs/kbfscrypto"
)

// SimpleFS is the simple filesystem rpc layer implementation.
type SimpleFS struct {
	lock       sync.RWMutex
	config     Config
	handles    map[keybase1.OpID]*handle
	inProgress map[keybase1.OpID]*inprogress
	log        logger.Logger
}

type inprogress struct {
	desc keybase1.OpDescription
	done chan error
}

type handle struct {
	node  Node
	async interface{}
	path  keybase1.Path
}

// make sure the interface is implemented
var _ keybase1.SimpleFSInterface = (*SimpleFS)(nil)

func newSimpleFS(config Config) *SimpleFS {
	log := config.MakeLogger("simplefs")
	return &SimpleFS{
		config:     config,
		handles:    map[keybase1.OpID]*handle{},
		inProgress: map[keybase1.OpID]*inprogress{},
		log:        log,
	}
}

// SimpleFSList - Begin list of items in directory at path
// Retrieve results with readList()
// Cannot be a single file to get flags/status,
// must be a directory.
func (k *SimpleFS) SimpleFSList(_ context.Context, arg keybase1.SimpleFSListArg) error {
	return k.startAsync(arg.OpID, keybase1.NewOpDescriptionWithList(
		keybase1.ListArgs{
			OpID: arg.OpID, Path: arg.Path,
		}), func(ctx context.Context) (err error) {
		var children map[string]EntryInfo

		rawPath := arg.Path.Kbfs()
		wantPublic := false
		switch {
		case rawPath == `/public`:
			wantPublic = true
			fallthrough
		case rawPath == `/private`:
			children, err = k.favoriteList(ctx, arg.Path, wantPublic)
		default:
			node, ei, err := k.getRemoteNode(ctx, arg.Path)
			if err != nil {
				return err
			}
			switch ei.Type {
			case Dir:
				children, err = k.config.KBFSOps().GetDirChildren(ctx, node)
			default:
				children = map[string]EntryInfo{stdpath.Base(arg.Path.Kbfs()): ei}
			}
		}
		if err != nil {
			return err
		}
		var des = make([]keybase1.Dirent, len(children))
		var i = 0
		for name, ei := range children {
			setStat(&des[i], &ei)
			des[i].Name = name
			i++
		}

		k.setResult(arg.OpID, keybase1.SimpleFSListResult{Entries: des})
		return nil
	})
}

func (k *SimpleFS) favoriteList(ctx context.Context, path keybase1.Path, wantPublic bool) (map[string]EntryInfo, error) {
	session, err := k.config.KBPKI().GetCurrentSession(ctx)
	// Return empty directory listing if we are not logged in.
	if err != nil {
		return nil, nil
	}

	favs, err := k.config.KBFSOps().GetFavorites(ctx)
	if err != nil {
		return nil, err
	}

	res := make(map[string]EntryInfo, len(favs))
	for _, fav := range favs {
		if fav.Public != wantPublic {
			continue
		}
		pname, err := FavoriteNameToPreferredTLFNameFormatAs(
			session.Name, CanonicalTlfName(fav.Name))
		if err != nil {
			k.log.Errorf("FavoriteNameToPreferredTLFNameFormatAs: %q %v", fav.Name, err)
			continue
		}
		res[string(pname)] = EntryInfo{Type: Dir}
	}
	return res, nil
}

// SimpleFSListRecursive - Begin recursive list of items in directory at path
func (k *SimpleFS) SimpleFSListRecursive(ctx context.Context, arg keybase1.SimpleFSListRecursiveArg) error {
	return k.startAsync(arg.OpID, keybase1.NewOpDescriptionWithListRecursive(
		keybase1.ListArgs{
			OpID: arg.OpID, Path: arg.Path,
		}), func(ctx context.Context) (err error) {

		// A stack of paths to process - ordering does not matter.
		// Here we don't walk symlinks, so no loops possible.
		var paths = []keybase1.Path{arg.Path}
		var des []keybase1.Dirent
		for len(paths) > 0 {
			// Take last element and shorten
			path := paths[len(paths)-1]
			paths = paths[:len(paths)-1]
			node, _, err := k.getRemoteNode(ctx, path)
{'fraction_non_alphanumeric': 0.1191702221568339, 'fraction_numerical': 0.008974547594526996, 'mean_word_length': 3.6979958534899793, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3350538', 'n_tokens_mistral': 2560, 'n_tokens_neox': 2349, 'n_words': 639}