drivefs

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 14, 2024 License: MIT Imports: 14 Imported by: 0

README

drivefs

Implements google drive to fs.FS

Path resolve

Google drive does not implement the file system in the unix filepath format, so we have to resolve this path, this can become costly for the API, we have to make a call for each separator (N+MS+1), so this will end up becoming slow to resolve (This path being /Frog/Google/files, it would be the same as 3 + 0.5ms + 1, total of 2.5ms), for this we have a cache of files in the folder that reduces this time but leaves it undone with the time

Example

package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"net"
	"net/http"
	"net/netip"
	"os"

	"golang.org/x/oauth2"
	"google.golang.org/api/drive/v3"
	"sirherobrine23.org/Sirherobrine23/drivefs"
)

var configPath string
var serverPort uint

func main() {
	flag.StringVar(&configPath, "config", "./config.json", "Config file path")
	flag.UintVar(&serverPort, "port", 8081, "server to listen")
	flag.Parse()

	var ggdrive *drivefs.Gdrive = new(drivefs.Gdrive)
	file, err := os.Open(configPath)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	if err := json.NewDecoder(file).Decode(ggdrive); err != nil {
		panic(err)
	}

	if ggdrive.GoogleToken != nil {
		var err error
		if ggdrive, err = drivefs.New(ggdrive.GoogleOAuth, *ggdrive.GoogleToken); err != nil {
			panic(err)
		}
	} else {
		ln, err := net.Listen("tcp", ":0")
		if err != nil {
			panic(err)
		}
		P, _ := netip.ParseAddrPort(ln.Addr().String())
		ln.Close()
		ggdrive.GoogleOAuth.Redirects = []string{fmt.Sprintf("http://localhost:%d/callback", P.Port())}

		config := &oauth2.Config{ClientID: ggdrive.GoogleOAuth.Client, ClientSecret: ggdrive.GoogleOAuth.Secret, RedirectURL: ggdrive.GoogleOAuth.Redirects[0], Scopes: []string{drive.DriveScope, drive.DriveFileScope}, Endpoint: oauth2.Endpoint{AuthURL: ggdrive.GoogleOAuth.AuthURI, TokenURL: ggdrive.GoogleOAuth.TokenURI}}

		authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
		fmt.Printf("Go to the following link in your browser then type the authorization code: \n%v\n", authURL)

		var server *http.Server
		var code string
		mux := http.NewServeMux()
		mux.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", "text/plain")
			w.WriteHeader(200)
			w.Write([]byte("Doned\n"))
			code = r.URL.Query().Get("code")
			if code != "" {
				fmt.Printf("Code: %q\n", code)
				server.Close()
			}
		})

		server = &http.Server{Addr: P.String(), Handler: mux}
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			panic(err)
		}

		ggdrive.GoogleToken, err = config.Exchange(context.TODO(), code)
		if err != nil {
			panic(fmt.Errorf("unable to retrieve token from web %v", err))
		}

		file.Close()
		if file, err = os.Create(configPath); err != nil {
			panic(err)
		}

		at := json.NewEncoder(file)
		at.SetIndent("", "  ")
		if err := at.Encode(ggdrive); err != nil {
			panic(err)
		}
	}

	fmt.Printf("server listening on :%d\n", serverPort)
	if err := http.ListenAndServe(fmt.Sprintf(":%d", serverPort), http.FileServerFS(ggdrive)); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}
}

Documentation

Index

Constants

View Source
const (
	MimeFolder  string = "application/vnd.google-apps.folder"   // Folder mimetype
	MimeSyslink string = "application/vnd.google-apps.shortcut" // Syslink/hardlink
)

Variables

View Source
var ErrGoogletoken = errors.New("require oauth2.Token in struct")

Functions

This section is empty.

Types

type DriveInfo

type DriveInfo struct {
	// contains filtered or unexported fields
}

func (DriveInfo) IsDir

func (entry DriveInfo) IsDir() bool

func (DriveInfo) MarshalText

func (entry DriveInfo) MarshalText() ([]byte, error)

func (DriveInfo) ModTime

func (entry DriveInfo) ModTime() time.Time

func (DriveInfo) Mode

func (entry DriveInfo) Mode() fs.FileMode

func (DriveInfo) Name

func (entry DriveInfo) Name() string

func (DriveInfo) Size

func (entry DriveInfo) Size() int64

func (DriveInfo) Sys

func (entry DriveInfo) Sys() any

type DriveOpen

type DriveOpen struct {
	// contains filtered or unexported fields
}

func (*DriveOpen) Close

func (file *DriveOpen) Close() error

func (*DriveOpen) Read

func (file *DriveOpen) Read(p []byte) (int, error)

func (*DriveOpen) ReadDir

func (file *DriveOpen) ReadDir(n int) ([]fs.DirEntry, error)

func (DriveOpen) Stat

func (file DriveOpen) Stat() (fs.FileInfo, error)

type Gdrive

type Gdrive struct {
	GoogleOAuth GoogleApp     `json:"installed"`       // Google oauth app
	GoogleToken *oauth2.Token `json:"token,omitempty"` // User authe token
	// contains filtered or unexported fields
}

func New

func New(app GoogleApp, gToken oauth2.Token) (*Gdrive, error)

Create new Gdrive struct and configure google drive client

func (*Gdrive) Open

func (gdrive *Gdrive) Open(fpath string) (fs.File, error)

func (*Gdrive) ReadDir

func (gdrive *Gdrive) ReadDir(fpath string) ([]fs.DirEntry, error)

func (*Gdrive) ReadFile

func (gdrive *Gdrive) ReadFile(fpath string) ([]byte, error)

func (*Gdrive) Stat

func (gdrive *Gdrive) Stat(fpath string) (fs.FileInfo, error)

func (*Gdrive) Sub

func (gdrive *Gdrive) Sub(fpath string) (fs.FS, error)

Fork gdrive app and set different `rootDrive` from `my drive` to Folder, only FOLDER

Sub returns an FS corresponding to the subtree rooted at dir.

type GoogleApp

type GoogleApp struct {
	Client    string   `json:"client_id"`
	Secret    string   `json:"client_secret"`
	Project   string   `json:"project_id"`
	AuthURI   string   `json:"auth_uri"`
	TokenURI  string   `json:"token_uri"`
	CertURI   string   `json:"auth_provider_x509_cert_url"`
	Redirects []string `json:"redirect_uris"`
}

Directories

Path Synopsis
internal
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL