@@ -1,8 +1,16 @@
|
||||
/// <reference types="@javatypes/spring-data-redis" />
|
||||
|
||||
import { constants, plugin as pluginApi, amqp, server, web } from '@ccms/api'
|
||||
import { plugin, interfaces, cmd } from '@ccms/plugin'
|
||||
import { AmqpAdmin, ConnectionFactoryAdapter, AmqpManager } from '@ccms/amqp'
|
||||
import { inject, Autowired } from '@ccms/container'
|
||||
import { Server } from '@ccms/web'
|
||||
import { inject, Autowired, ContainerInstance, Container } from '@ccms/container'
|
||||
import { Server, Controller, Get, Param, METADATA_KEY } from '@ccms/web'
|
||||
|
||||
const SearchRankingAmqpAdmin = Symbol('SearchRanking-AmqpAdmin')
|
||||
|
||||
const EXCHANGE_NAME = `search.ranking.${process.env.SPRING_CLOUD_CONFIG_PROFILE || 'dev'}`
|
||||
const QUEUE_NAME = `search.ranking.${process.env.SPRING_CLOUD_CONFIG_PROFILE || 'dev'}`
|
||||
const ROUTER_KEY = `search.ranking.${process.env.SPRING_CLOUD_CONFIG_PROFILE || 'dev'}`
|
||||
|
||||
@plugin({ name: SearchRanking.name, version: SearchRanking.version, author: SearchRanking.author, servers: SearchRanking.servers, source: __filename })
|
||||
export class SearchRanking extends interfaces.Plugin {
|
||||
@@ -10,6 +18,8 @@ export class SearchRanking extends interfaces.Plugin {
|
||||
public static author = 'MiaoWoo'
|
||||
public static servers = [constants.ServerType.Spring]
|
||||
|
||||
@inject(ContainerInstance)
|
||||
private container: Container
|
||||
@inject(pluginApi.PluginManager)
|
||||
private pluginManager: pluginApi.PluginManager
|
||||
@inject(amqp.Manager)
|
||||
@@ -20,17 +30,11 @@ export class SearchRanking extends interfaces.Plugin {
|
||||
private webServer: Server
|
||||
|
||||
@Autowired()
|
||||
private mongoTemplate: any
|
||||
@Autowired()
|
||||
private redisTemplate: any
|
||||
private redisTemplate: org.springframework.data.redis.core.RedisTemplate<string, any>
|
||||
|
||||
private amqpAdmin: AmqpAdmin
|
||||
private listener: org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer
|
||||
|
||||
private readonly exchangeName = 'search.ranking'
|
||||
private readonly queueName = 'search.ranking'
|
||||
private readonly routerKey = 'search.ranking'
|
||||
|
||||
load() {
|
||||
let connection = new ConnectionFactoryAdapter({
|
||||
url: 'amqp://rabbitmq.c.sixi.com:5672',
|
||||
@@ -42,33 +46,26 @@ export class SearchRanking extends interfaces.Plugin {
|
||||
}
|
||||
|
||||
enable() {
|
||||
this.webServer.registryMapping('/api/search', (ctx) => {
|
||||
if (!ctx.params.keyword) { return { status: 400, msg: '查询关键词不得为空!' } }
|
||||
let keyword = ctx.params.keyword + ''
|
||||
let type = ctx.params.type == 'sale' ? 'sale' : 'normal'
|
||||
let time = parseInt(ctx.params.time + '') || 60 * 60 * 24 * 15
|
||||
return this.cacheAndSearch(keyword, type as any, time * 1000)
|
||||
})
|
||||
this.webServer.registryMapping('/api/search/ranking', (ctx) => {
|
||||
if (!ctx.params.keyword || !ctx.params.shopName) { return { status: 400, msg: '查询关键词不得为空!' } }
|
||||
let keyword = ctx.params.keyword + ''
|
||||
let shopName = ctx.params.shopName + ''
|
||||
let type = ctx.params.type == 'sale' ? 'sale' : 'normal'
|
||||
let time = parseInt(ctx.params.time + '') || 60 * 60 * 24 * 15
|
||||
return this.sendSearchRankingCmd(keyword, shopName, type as any, time * 1000)
|
||||
})
|
||||
this.amqpAdmin.declareQueueAndBindExchange(this.queueName, this.exchangeName, this.routerKey)
|
||||
this.amqpAdmin.declareBinding(this.queueName, 'client.topic.exchange', `cmd_res.${this.routerKey}`)
|
||||
this.listener = this.amqpAdmin.createContainer<string>(this.queueName, (content, message, channel) => {
|
||||
this.amqpAdmin.declareQueueAndBindExchange(QUEUE_NAME, EXCHANGE_NAME, ROUTER_KEY)
|
||||
this.amqpAdmin.declareBinding(QUEUE_NAME, 'client.topic.exchange', `cmd_res.${ROUTER_KEY}`)
|
||||
this.listener = this.amqpAdmin.createContainer<string>(QUEUE_NAME, (content, _message, _channel) => {
|
||||
let searchResult = JSON.parse(content)
|
||||
if (searchResult.type == "company") {
|
||||
this.logger.info(content)
|
||||
return
|
||||
}
|
||||
this.redisTemplate.opsForValue().set(searchResult.reqData.cacheKey, searchResult)
|
||||
this.logger.sender(this.Server.getConsoleSender(), `§6查询任务完成! §b关键词: §r${searchResult.reqData.keywords}`)
|
||||
})
|
||||
this.container.bind(SearchRankingAmqpAdmin).toConstantValue(this.amqpAdmin)
|
||||
this.listener.start()
|
||||
this.webServer.registryController(SearchRankingController)
|
||||
}
|
||||
|
||||
disable() {
|
||||
this.container.unbind(SearchRankingAmqpAdmin)
|
||||
this.listener.stop()
|
||||
this.webServer.unregistryController(SearchRankingController)
|
||||
}
|
||||
|
||||
@cmd()
|
||||
@@ -90,14 +87,55 @@ export class SearchRanking extends interfaces.Plugin {
|
||||
this.pluginManager.reload(this)
|
||||
}
|
||||
|
||||
cmdsend(sender: any, ...args: string[]) {
|
||||
}
|
||||
|
||||
cmdsearch(sender: any, keyword: string, type: "sale" | "normal" = "sale", time: number) {
|
||||
this.logger.sender(sender, this.cacheAndSearch(keyword, type, time)?.msg)
|
||||
this.logger.sender(sender, this.container.getNamed<SearchRankingController>(METADATA_KEY.Controller, SearchRankingController.name).cacheAndSearch(keyword, type, time)?.msg)
|
||||
}
|
||||
}
|
||||
|
||||
@Controller({ path: '/api', name: SearchRankingController.name })
|
||||
class SearchRankingController {
|
||||
@Autowired()
|
||||
private redisTemplate: org.springframework.data.redis.core.RedisTemplate<string, any>
|
||||
|
||||
@inject(SearchRankingAmqpAdmin)
|
||||
private amqpAdmin: AmqpAdmin
|
||||
|
||||
@Get()
|
||||
public search(
|
||||
@Param({ name: 'keyword', require: true, message: '查询关键词不得为空!' }) keyword: string,
|
||||
@Param("type") type: string = 'normal',
|
||||
@Param('time') time: number = 60 * 60 * 24 * 15
|
||||
) {
|
||||
return this.cacheAndSearch(keyword, type as any, time * 1000)
|
||||
}
|
||||
|
||||
private cacheAndSearch(keyword: string, type: string = "sale", time: number = 15 * 24 * 60 * 60 * 1000) {
|
||||
@Get("/search/ranking")
|
||||
public searchRanking(
|
||||
@Param({ name: 'keyword', require: true, message: '查询关键词不得为空!' }) keyword: string,
|
||||
@Param("shopName") shopName: string = 'normal',
|
||||
@Param("type") type: string = 'normal',
|
||||
@Param('time') time: number = 60 * 60 * 24 * 15
|
||||
) {
|
||||
return this.sendSearchRankingCmd(keyword, shopName, type as any, time * 1000)
|
||||
}
|
||||
|
||||
@Get('/search/company')
|
||||
public searchCompany(
|
||||
@Param('url') url: string
|
||||
) {
|
||||
this.amqpAdmin.getTemplate().convertAndSend('client.topic.exchange', 'cmd_req', {
|
||||
cmd: 'scout._1688CompanyInfo',
|
||||
data: {
|
||||
type: 'company',
|
||||
url: url,
|
||||
cacheKey: 'SearchRanking:company'
|
||||
},
|
||||
resRouteSuffix: ROUTER_KEY,
|
||||
target: {}
|
||||
})
|
||||
}
|
||||
|
||||
public cacheAndSearch(keyword: string, type: string = "sale", time: number = 15 * 24 * 60 * 60 * 1000) {
|
||||
let cacheKey = this.getCacheKey(keyword, type)
|
||||
if (this.redisTemplate.hasKey(cacheKey)) {
|
||||
let lastSearchTime = this.redisTemplate.opsForValue().get(cacheKey)
|
||||
@@ -143,7 +181,7 @@ export class SearchRanking extends interfaces.Plugin {
|
||||
} : {},
|
||||
cacheKey: this.getResultCacheKey(keywords, type, dateCache)
|
||||
},
|
||||
resRouteSuffix: this.routerKey,
|
||||
resRouteSuffix: ROUTER_KEY,
|
||||
target: {}
|
||||
})
|
||||
}
|
||||
@@ -159,11 +197,10 @@ export class SearchRanking extends interfaces.Plugin {
|
||||
cacheKey: this.getResultCacheKey(keywords, type, cacheTime),
|
||||
cacheTime
|
||||
},
|
||||
resRouteSuffix: this.routerKey,
|
||||
resRouteSuffix: ROUTER_KEY,
|
||||
target: {}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得关键词+类型的上次查询时间
|
||||
* @param keywords 关键词
|
||||
@@ -175,4 +212,4 @@ export class SearchRanking extends interfaces.Plugin {
|
||||
private getResultCacheKey(keywords: string, type: string, date: number) {
|
||||
return `SearchRanking:${keywords}:${type}:${date}`
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user