/
fileUtils.go
127 lines (116 loc) · 3.47 KB
/
fileUtils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package util
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/gorilla/websocket"
"github.com/hpcloud/tail"
)
var (
// FileList - list of files that were parsed from the provided config
FileList []string
visited map[string]bool
// Global Map that stores all the files, used to skip duplicates while
// subsequent indexing attempts in cron trigger
indexMap = make(map[string]bool)
)
// TailFile - Accepts a websocket connection and a filename and tails the
// file and writes the changes into the connection. Recommended to run on
// a thread as this is blocking in nature
func TailFile(conn *websocket.Conn, fileName string) {
t, err := tail.TailFile(fileName,
tail.Config{
Follow: true,
Location: &tail.SeekInfo{
Whence: os.SEEK_END,
},
})
if err != nil {
fmt.Fprintln(os.Stderr, "Error occurred in opening the file: ", err)
}
for line := range t.Lines {
conn.WriteMessage(websocket.TextMessage, []byte(line.Text))
}
}
// IndexFiles - takes argument as a list of files and directories and returns
// a list of absolute file strings to be tailed
func IndexFiles(fileList []string) error {
// Re-initialize the visited array
visited = make(map[string]bool)
// marking all entries possible stale
// will be removed if not updated
for k := range indexMap {
indexMap[k] = false
}
for _, file := range fileList {
dfs(file)
}
// Re-initialize the file list array
FileList = make([]string, 0)
// Iterate through the map that contains the filenames
for k, v := range indexMap {
if v == false {
delete(indexMap, k)
continue
}
fmt.Fprintln(os.Stderr, k)
FileList = append(FileList, k)
}
Conf.Dir = FileList
fmt.Fprintln(os.Stderr, "Indexing complete !, file index length: ", len(Conf.Dir))
return nil
}
/* skip all files that are :
a: append-only
l: exclusive use
T: temporary file; Plan 9 only
L: symbolic link
D: device file
p: named pipe (FIFO)
S: Unix domain socket
u: setuid
g: setgid
c: Unix character device, when ModeDevice is set
t: sticky
*/
func dfs(file string) {
// Mostly useful for first entry, as the paths may be like ../dir or ~/path/../dir
// or some wierd *nixy style, Once the file is cleaned and made into an absolute
// path, it should be safe as the next call is basepath(abspath) + "/" + name of
// the file which should be accurate in all terms and absolute without any
// funky conversions used in OS
file = filepath.Clean(file)
absPath, err := filepath.Abs(file)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to get absolute path of the file %s; err: %s\n", file, err)
}
if _, ok := visited[file]; ok {
// if the absolute path has been visited, return without processing
return
}
visited[file] = true
s, err := os.Stat(absPath)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to stat file %s; err: %s\n", file, err)
return
}
// check if the file is a directory
if s.IsDir() {
basepath := filepath.Clean(file)
filelist, _ := ioutil.ReadDir(absPath)
for _, f := range filelist {
dfs(basepath + string(os.PathSeparator) + f.Name())
}
} else if strings.ContainsAny(s.Mode().String(), "alTLDpSugct") {
// skip these files
// @TODO try including names PIPES
} else {
// only remaining file are ascii files that can be then differentiated
// by the user as golang has only these many categorization
// Note : this appends the absolute paths
// Insert the absPath into the Map, avoids duplicates in successive cron runs
indexMap[absPath] = true
}
}