-
Notifications
You must be signed in to change notification settings - Fork 96
/
listinfomap.go
132 lines (114 loc) · 3.48 KB
/
listinfomap.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
128
129
130
131
132
package main
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
router "github.com/v2fly/v2ray-core/v5/app/router/routercommon"
)
// ListInfoMap is the map of files in data directory and ListInfo
type ListInfoMap map[fileName]*ListInfo
// Marshal processes a file in data directory and generates ListInfo for it.
func (lm *ListInfoMap) Marshal(path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
list := NewListInfo()
listName := fileName(strings.ToUpper(filepath.Base(path)))
list.Name = listName
if err := list.ProcessList(file); err != nil {
return err
}
(*lm)[listName] = list
return nil
}
// FlattenAndGenUniqueDomainList flattens the included lists and
// generates a domain trie for each file in data directory to
// make the items of domain type list unique.
func (lm *ListInfoMap) FlattenAndGenUniqueDomainList() error {
inclusionLevel := make([]map[fileName]bool, 0, 20)
okayList := make(map[fileName]bool)
inclusionLevelAllLength, loopTimes := 0, 0
for inclusionLevelAllLength < len(*lm) {
inclusionMap := make(map[fileName]bool)
if loopTimes == 0 {
for _, listinfo := range *lm {
if listinfo.HasInclusion {
continue
}
inclusionMap[listinfo.Name] = true
}
} else {
for _, listinfo := range *lm {
if !listinfo.HasInclusion || okayList[listinfo.Name] {
continue
}
var passTimes int
for filename := range listinfo.InclusionAttributeMap {
if !okayList[filename] {
break
}
passTimes++
}
if passTimes == len(listinfo.InclusionAttributeMap) {
inclusionMap[listinfo.Name] = true
}
}
}
for filename := range inclusionMap {
okayList[filename] = true
}
inclusionLevel = append(inclusionLevel, inclusionMap)
inclusionLevelAllLength += len(inclusionMap)
loopTimes++
}
for idx, inclusionMap := range inclusionLevel {
fmt.Printf("Level %d:\n", idx+1)
fmt.Println(inclusionMap)
fmt.Println()
for inclusionFilename := range inclusionMap {
if err := (*lm)[inclusionFilename].Flatten(lm); err != nil {
return err
}
}
}
return nil
}
// ToProto generates a router.GeoSite for each file in data directory
// and returns a router.GeoSiteList
func (lm *ListInfoMap) ToProto(excludeAttrs map[fileName]map[attribute]bool) *router.GeoSiteList {
protoList := new(router.GeoSiteList)
for _, listinfo := range *lm {
listinfo.ToGeoSite(excludeAttrs)
protoList.Entry = append(protoList.Entry, listinfo.GeoSite)
}
return protoList
}
// ToPlainText returns a map of exported lists that user wants
// and the contents of them in byte format.
func (lm *ListInfoMap) ToPlainText(exportListsMap []string) (map[string][]byte, error) {
filePlainTextBytesMap := make(map[string][]byte)
for _, filename := range exportListsMap {
if listinfo := (*lm)[fileName(strings.ToUpper(filename))]; listinfo != nil {
plaintextBytes := listinfo.ToPlainText()
filePlainTextBytesMap[filename] = plaintextBytes
} else {
fmt.Println("Notice: " + filename + ": no such exported list in the directory, skipped.")
}
}
return filePlainTextBytesMap, nil
}
// ToGFWList returns the content of the list to be generated into GFWList format
// that user wants in bytes format.
func (lm *ListInfoMap) ToGFWList(togfwlist string) ([]byte, error) {
if togfwlist != "" {
if listinfo := (*lm)[fileName(strings.ToUpper(togfwlist))]; listinfo != nil {
return listinfo.ToGFWList(), nil
}
return nil, errors.New("no such list: " + togfwlist)
}
return nil, nil
}