This commit is contained in:
xing 2022-07-26 12:31:47 +08:00
parent ab97f5c624
commit eceeae2444
2 changed files with 94 additions and 25 deletions

57
main.go
View File

@ -36,21 +36,24 @@ type dataChan struct {
} }
type fetchHandler struct { type fetchHandler struct {
fetchUrl string
hadFetchData []data.FetchData hadFetchData []data.FetchData
cronTime mapXS[time.Duration] cronTime mapXS[time.Duration]
keyword mapXS[string] keyword mapXS[string]
searchSource mapXS[[]string]
hadFetchedMap mapXS[int] hadFetchedMap mapXS[int]
reloadCron mapXS[chan int] reloadCron mapXS[chan int]
isOff chan int isOff chan int
rMsgChan chan connChan rMsgChan chan connChan
newFetchItem chan dataChan newFetchItem chan dataChan
connMap mapXS[*websocket.Conn] connMap mapXS[*websocket.Conn]
sourceMap map[string]newsource.Source
sourceArr []string
} }
type setting struct { type setting struct {
Keyword string `json:"keyword"` Keyword string `json:"keyword"`
TimeStep int `json:"timeStep"` TimeStep int `json:"timeStep"`
SearchSource []string `json:"searchSource"`
} }
type message struct { type message struct {
@ -86,6 +89,15 @@ func (r dist) Open(name string) (fs.File, error) {
return file, err return file, err
} }
func isContain[T comparable](i T, arr []T) bool {
for _, t := range arr {
if i == t {
return true
}
}
return false
}
func setMap[T mapT](obj *mapXS[T], key string, v T) { func setMap[T mapT](obj *mapXS[T], key string, v T) {
obj.Lock() obj.Lock()
(*obj.mapX)[key] = v (*obj.mapX)[key] = v
@ -99,7 +111,7 @@ func delMap[T mapT](obj *mapXS[T], key string) {
} }
type mapT interface { type mapT interface {
string | int | time.Duration | *websocket.Conn | chan int string | []string | int | time.Duration | *websocket.Conn | chan int
} }
type mapX[T mapT] map[string]T type mapX[T mapT] map[string]T
@ -108,9 +120,16 @@ type mapXS[T mapT] struct {
*sync.Mutex *sync.Mutex
} }
func newFetchHandler(fetchUrl string) *fetchHandler { func newFetchHandler() *fetchHandler {
var arr = make(map[string]newsource.Source)
var x []string
for _, source := range newsource.GetSource() {
arr[source.Name] = source
x = append(x, source.Name)
}
return &fetchHandler{ return &fetchHandler{
fetchUrl: fetchUrl, sourceMap: arr,
sourceArr: x,
keyword: mapXS[string]{ keyword: mapXS[string]{
&mapX[string]{}, &mapX[string]{},
&sync.Mutex{}, &sync.Mutex{},
@ -123,6 +142,10 @@ func newFetchHandler(fetchUrl string) *fetchHandler {
&mapX[time.Duration]{}, &mapX[time.Duration]{},
&sync.Mutex{}, &sync.Mutex{},
}, },
searchSource: mapXS[[]string]{
&mapX[[]string]{},
&sync.Mutex{},
},
reloadCron: mapXS[chan int]{ reloadCron: mapXS[chan int]{
&mapX[chan int]{}, &mapX[chan int]{},
&sync.Mutex{}, &sync.Mutex{},
@ -142,7 +165,8 @@ func (f *fetchHandler) handle(conn string) {
if kk, ok := (*f.keyword.mapX)[conn]; ok && kk != "" { if kk, ok := (*f.keyword.mapX)[conn]; ok && kk != "" {
key = kk key = kk
} }
for _, source := range newsource.GetSource() { for _, sourceName := range (*f.searchSource.mapX)[conn] {
source := f.sourceMap[sourceName]
r := f.fetch2(source, key) r := f.fetch2(source, key)
if r != nil { if r != nil {
if strings.ToUpper(source.Type) == "HTML" { if strings.ToUpper(source.Type) == "HTML" {
@ -160,9 +184,10 @@ func (f *fetchHandler) receiveMsg() {
switch r.msg.Action { switch r.msg.Action {
case "search": case "search":
if t, ok := r.msg.Data.(*setting); ok { if t, ok := r.msg.Data.(*setting); ok {
(*f.reloadCron.mapX)[r.conn] <- t.TimeStep
setMap[string](&f.keyword, r.conn, t.Keyword) setMap[string](&f.keyword, r.conn, t.Keyword)
setMap[[]string](&f.searchSource, r.conn, t.SearchSource)
f.handle(r.conn) f.handle(r.conn)
(*f.reloadCron.mapX)[r.conn] <- t.TimeStep
} }
} }
} }
@ -283,6 +308,7 @@ func (f *fetchHandler) parseAjax(response *http.Response, source newsource.Sourc
} }
if len(newFetch) > 0 { if len(newFetch) > 0 {
var newF []data.FetchData
for i := 0; i < len(newFetch); i++ { for i := 0; i < len(newFetch); i++ {
fetchData := newFetch[i] fetchData := newFetch[i]
k := conn + "_" + fetchData.Url + "_" + fetchData.Title k := conn + "_" + fetchData.Url + "_" + fetchData.Title
@ -295,13 +321,12 @@ func (f *fetchHandler) parseAjax(response *http.Response, source newsource.Sourc
if _, ok := (*f.hadFetchedMap.mapX)[k]; !ok { if _, ok := (*f.hadFetchedMap.mapX)[k]; !ok {
f.hadFetchData = append(f.hadFetchData, fetchData) f.hadFetchData = append(f.hadFetchData, fetchData)
setMap(&f.hadFetchedMap, k, 1) setMap(&f.hadFetchedMap, k, 1)
} else { newF = append(newF, newFetch[i])
newFetch = newFetch[:i+copy(newFetch[i:], newFetch[i+1:])] // 删除中间1个元素
} }
} }
f.newFetchItem <- dataChan{ f.newFetchItem <- dataChan{
conn: conn, conn: conn,
item: newFetch, item: newF,
} }
} }
err := response.Body.Close() err := response.Body.Close()
@ -389,7 +414,7 @@ func (f *fetchHandler) cronFetch(conn string, c chan int) {
} }
func main() { func main() {
h := newFetchHandler("https://www.baidu.com/s?rtt=1&bsst=1&cl=2&tn=news&rsv_dl=ns_pc&word=") h := newFetchHandler()
router := gin.Default() router := gin.Default()
static := dist{ static := dist{
FS: st, FS: st,
@ -430,6 +455,12 @@ func main() {
log.Println(err) log.Println(err)
return return
} }
_ = conn.WriteJSON(message{
Status: true,
Action: "sourceList",
Message: "",
Data: h.sourceArr,
})
remote := conn.RemoteAddr().String() remote := conn.RemoteAddr().String()
if _, ok := (*h.connMap.mapX)[remote]; !ok { if _, ok := (*h.connMap.mapX)[remote]; !ok {
setMap(&h.connMap, remote, conn) setMap(&h.connMap, remote, conn)
@ -460,12 +491,12 @@ func main() {
}) })
go func() { go func() {
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
url := "http://127.0.0.1:8080" u := "http://127.0.0.1:8080"
switch runtime.GOOS { switch runtime.GOOS {
case "linux": case "linux":
exec.Command(`xdg-open`, url).Start() exec.Command(`xdg-open`, u).Start()
case "windows": case "windows":
exec.Command(`cmd`, `/c`, `start`, url).Start() exec.Command(`cmd`, `/c`, `start`, u).Start()
} }

View File

@ -8,12 +8,29 @@
<el-form-item prop="password" label="搜索间隔时间,单位为秒"> <el-form-item prop="password" label="搜索间隔时间,单位为秒">
<el-input v-model="form.timeStep" type="number" step="1" ></el-input> <el-input v-model="form.timeStep" type="number" step="1" ></el-input>
</el-form-item> </el-form-item>
<el-form-item prop="searchSource" label="要抓取的新闻源">
<el-select
v-model="form.searchSource"
multiple
clearable filterable
placeholder="可多选"
style="width: 240px"
>
<el-option
v-for="item in allSource"
:key="item.k"
:label="item.k"
:value="item.v"
/>
</el-select>
</el-form-item>
<el-form-item class="btns"> <el-form-item class="btns">
<el-button @click="submit" type="primary">查询</el-button> <el-button @click="submit" type="primary">查询</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-card class="box-card"> <el-card class="box-card">
<el-table <el-table :table-layout="tableLayout"
:data="rowss" border stripe :data="rowss" border stripe
style="width: 100%"> style="width: 100%">
<el-table-column <el-table-column
@ -32,12 +49,14 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
align="center"
prop="source" prop="source"
label="来源"> label="来源">
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="desc" prop="desc"
label="描述" label="描述"
:show-overflow-tooltip="true"
> >
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@ -64,14 +83,20 @@
</template> </template>
<script> <script>
import {ref} from 'vue'
const tableLayout = ref('auto')
export default { export default {
name: 'WelCome', name: 'WelCome',
data () { data () {
return { return {
tableLayout: tableLayout,
form: { form: {
keyword: '纪检', keyword: '纪检',
timeStep: 60 timeStep: 60,
searchSource: [],
}, },
allSource: [],
ws: null, ws: null,
formRules: { formRules: {
keyword: [ keyword: [
@ -81,6 +106,9 @@ export default {
timeStep: [ timeStep: [
{ required: true, message: '请输入时间间隔,单位为秒', trigger: 'blur' }, { required: true, message: '请输入时间间隔,单位为秒', trigger: 'blur' },
{ min: 1, max: 10000000, message: '长度在 1 到 10000000 秒', trigger: 'blur' } { min: 1, max: 10000000, message: '长度在 1 到 10000000 秒', trigger: 'blur' }
],
searchSource: [
{ required: true, message: '请选择新闻源', trigger: 'change' },
] ]
}, },
rows: [], rows: [],
@ -135,6 +163,14 @@ export default {
this.ws = new WebSocket('ws://127.0.0.1:8080/ws') this.ws = new WebSocket('ws://127.0.0.1:8080/ws')
this.ws.addEventListener('message', e => { this.ws.addEventListener('message', e => {
const msg = JSON.parse(e.data) const msg = JSON.parse(e.data)
if(msg.Action==='sourceList'){
this.allSource = msg.Data.map(value => {
return {
k:value,
v:value
}
})
}else if (msg.Action==='newData'){
msg.Data.forEach(v => { msg.Data.forEach(v => {
v.isNew = true v.isNew = true
}) })
@ -143,6 +179,8 @@ export default {
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const n = new Notification('有新抓取文章', { body: msg.Data[0].title + '等总共' + msg.Data.length + '条' }) const n = new Notification('有新抓取文章', { body: msg.Data[0].title + '等总共' + msg.Data.length + '条' })
}) })
}
}) })
this.ws.onclose = () => { this.ws.onclose = () => {
const a = setInterval(() => { const a = setInterval(() => {