This commit is contained in:
2026-07-21 05:29:37 +03:00
commit edb875f197
299 changed files with 140638 additions and 0 deletions

875
daemon/onexbet.go Executable file
View File

@@ -0,0 +1,875 @@
package daemon
import (
"fmt"
"sort"
"strconv"
"strings"
"time"
"gordenko.dev/dima/flashscore"
"gordenko.dev/dima/onexbet"
"gordenko.dev/dima/tipper/model"
"gordenko.dev/dima/web/api"
"gordenko.dev/dima/ws"
)
func (s *Daemon) tryLinkToLiveMatch(sportID int, liveMatch onexbet.LiveMatch) {
matchName := fmt.Sprintf("%s - %s", liveMatch.Home, liveMatch.Away)
s.logger.Printf("try link: %s\n", matchName)
// Если уже распознан - пропускаем
// На всякий пожарный проверка
//_, ok := s.onexbetMatchToTeamMatch[liveMatch.MatchID]
//if ok {
// s.logger.Printf("try link: %s\n", matchName)
// return
//}
// Если этот матч уже проверяли - игнорируем
s.mutex.Lock()
unrecognizedMatches, ok := s.unrecognizedOnexbetMatches[sportID]
if !ok {
s.logger.Printf("unrecognized matches for the sport %d not found\n", sportID)
return
}
if unrecognizedMatches[liveMatch.MatchID] {
//s.logger.Printf("Match (%s) is unrecognized. Don't repeat identification\n", matchName)
s.mutex.Unlock()
return
}
s.mutex.Unlock()
homeTeamCandidates, err := s.fsmodel.ListTeamCandidates(sportID, liveMatch.Home)
if err != nil {
s.logger.Printf("fsmodel.ListFootballTeamCandidates: %s\n", err)
return
}
//s.logger.Printf("homeTeamCandidates (for %s): %q", liveMatch.Home, homeTeamCandidates)
awayTeamCandidates, err := s.fsmodel.ListTeamCandidates(sportID, liveMatch.Away)
if err != nil {
s.logger.Printf("fsmodel.ListFootballTeamCandidates: %s\n", err)
return
}
//s.logger.Printf("awayTeamCandidates (for %s): %q", liveMatch.Away, awayTeamCandidates)
//
teamMatches, ok := s.teamMatches[sportID]
if !ok {
err = fmt.Errorf("Not found matches for the sportID %d", sportID)
return
}
for _, match := range teamMatches {
var isTeamsSwapped bool
isIdentified := s.tryIdentifyMatch(match.Home.TeamID, match.Away.TeamID,
homeTeamCandidates, awayTeamCandidates)
if !isIdentified {
// Пробуем опознать если home и away поменять местами
isIdentified = s.tryIdentifyMatch(match.Home.TeamID, match.Away.TeamID,
awayTeamCandidates, homeTeamCandidates)
isTeamsSwapped = true
}
if isIdentified {
if !match.Home.WasLinked {
err = s.fsmodel.SetTeamWasLinked(match.Home.TeamID)
if err != nil {
s.logger.Printf("fsmodel.SetTeamWasLinked: %s; teamID=%s\n",
err, match.Home.TeamID)
}
s.mutex.Lock()
match.Home.WasLinked = true
s.mutex.Unlock()
}
if !match.Away.WasLinked {
err = s.fsmodel.SetTeamWasLinked(match.Away.TeamID)
if err != nil {
s.logger.Printf("fsmodel.SetTeamWasLinked: %s; teamID=%s\n",
err, match.Away.TeamID)
}
s.mutex.Lock()
match.Away.WasLinked = true
s.mutex.Unlock()
}
s.mutex.Lock()
match.IsLinkedToOnexbet = true
match.OnexbetMatchID = liveMatch.MatchID
match.OnexbetStatsMatchID = liveMatch.StatsMatchID
match.Score = liveMatch.Score
match.ScoreByPeriods = liveMatch.ScoreByPeriods
match.CurrentPeriod = liveMatch.CurrentPeriod
match.IsTeamsSwapped = isTeamsSwapped
s.onexbetMatchToTeamMatch[liveMatch.MatchID] = match
s.identifiedMatches[liveMatch.MatchID] = true
s.logger.Printf("Identified: %s; %s; %s\n", matchName, liveMatch.MatchID, match.MatchID)
// Матч опознан и перешел в inplay
s.publisher.Publish(
getChannel(match.SportID),
WSMessageInplayStatusChanged,
InplayStatusMessage{
MatchID: match.MatchID,
IsInplay: match.IsInplay,
IsLinkedToOnexbet: match.IsLinkedToOnexbet,
},
)
s.mutex.Unlock()
return
}
}
s.mutex.Lock()
// Кешируем негативный результат, чтобы не искать в базе ежеминутно
// Если пользователь распознает новые матчи, - кэш будет очищен
unrecognizedMatches, ok = s.unrecognizedOnexbetMatches[sportID]
if !ok {
return
}
unrecognizedMatches[liveMatch.MatchID] = true
s.mutex.Unlock()
s.logger.Printf("Match (%s; %s) is not identified. Added to unrecognized\n", matchName, liveMatch.MatchID)
}
func (s *Daemon) tryIdentifyMatch(homeTeamID, awayTeamID string, homeTeamCandidates, awayTeamCandidates []string) (_ bool) {
for _, candidateHomeTeamID := range homeTeamCandidates {
if homeTeamID == candidateHomeTeamID {
// Если нашли совпадение для home - ищем совпадение для away
for _, candidateAwayTeamID := range awayTeamCandidates {
if awayTeamID == candidateAwayTeamID {
// Mатч идентифицирован
return true
}
}
}
}
return
}
func (s *Daemon) onOnexbetWsClientConnected(conn *ws.Conn) {
s.logger.Printf("Onexbet Ws Client Connected\n")
}
/*
func (s *Daemon) onOnexbetMatchFinished(conn *ws.Conn, in onexbet.WatchReq) {
s.mutex.Lock()
defer s.mutex.Unlock()
match, ok := s.onexbetMatchToTeamMatch[in.MatchID]
if !ok {
return
}
match.IsInplay = false
}
*/
func (s *Daemon) onOnexbetTeamLiveMatches(conn *ws.Conn, in onexbet.LiveMatchesMessage) {
//s.logger.Println("onOnexbetTeamLiveMatches")
//s.logger.Printf("onexbetMatchToTeamMatch size: %d\n", len(s.onexbetMatchToTeamMatch))
sportID, ok := onexbetSportToFlashscoreSport[in.SportID]
if !ok {
s.logger.Printf("Bug: unknown OnexbetSport %d\n", in.SportID)
return
}
s.logger.Printf("Onexbet live matches: %d, watching: %d; Inplay: %d\n",
len(in.Matches), len(in.Watching), len(s.onexbetMatchToTeamMatch))
liveMap := make(map[string]onexbet.LiveMatch)
// В цикле рашем 3 задачи:
// - формируем словарь из live матчей на сайте 1xBet, для удобства дальнейшей обработки
// - для матчей в inplay проверяем не появился ли liveMatch.StatsMatchID, по которому
// можно будет узнать результат матча на сайте 1xBet
// - пытаемся распознать новые матчи
for _, liveMatch := range in.Matches {
liveMap[liveMatch.MatchID] = liveMatch
match, ok := s.onexbetMatchToTeamMatch[liveMatch.MatchID]
if ok {
s.logger.Printf("Match (%s - %s) already identified\n", match.Home.CanonicalName, match.Away.CanonicalName)
// ВАЖНО!
// liveMatch.StatsMatchID появится когда матч перейдет в лайв.
if match.OnexbetStatsMatchID == "" && liveMatch.StatsMatchID != "" {
match.OnexbetStatsMatchID = liveMatch.StatsMatchID
match.Score = liveMatch.Score
match.ScoreByPeriods = liveMatch.ScoreByPeriods
match.CurrentPeriod = liveMatch.CurrentPeriod
}
} else {
if !s.identifiedMatches[liveMatch.MatchID] {
// Матча нет среди распознанных - пытаемся опознать
s.tryLinkToLiveMatch(sportID, liveMatch)
}
}
}
var watchingMap = make(map[string]bool)
for _, onexbetMatchID := range in.Watching {
watchingMap[onexbetMatchID] = true
_, isMatchInInplay := s.onexbetMatchToTeamMatch[onexbetMatchID]
if !isMatchInInplay {
// Матча больше нет в inplay. Если 1xbet присылает его в Watching -
// значит API-запрос Unwatch где-то потерялся. Поэтому отправляем снова.
s.onexbetAPIClient.Call(api.CallReq{
FuncName: "unwatch",
In: onexbet.WatchReq{
SportID: in.SportID,
MatchID: onexbetMatchID,
},
})
}
}
// Цикл по inplay матчам
//if sportID == flashscore.Tennis {
//
//s.checkInplayTennisMatches(liveMap, watchingMap)
//} else {
s.checkInplayTeamMatches(sportID, in.SportID, liveMap, watchingMap)
//}
}
//func (s *Daemon) checkInplayTennisMatches(liveMap map[string]bool, watchingMap map[string]bool) {
//for onexbetMatchID, match := range s.onexbetMatchToTeamMatch {
//if match.
//}
//}
func (s *Daemon) checkInplayTeamMatches(sportID int, onexbetSportID onexbet.OnexbetSport, liveMap map[string]onexbet.LiveMatch, watchingMap map[string]bool) {
for onexbetMatchID, match := range s.onexbetMatchToTeamMatch {
if match.SportID != sportID {
// Если другой спорт - пропускаем матч
continue
}
liveMatch, isIn1xbetLive := liveMap[onexbetMatchID]
if !isIn1xbetLive {
// МАТЧИ могут просто исчезать из ЛАЙВ списка, поэтому просто удалять
// нельзя! Сперва запросим результат матча у 1xbet и решим что делать.
//err := s.processMatchDisappearedFromLive(match, onexbetMatchID)
//if err != nil {
// s.logger.Printf("processMatchDisappearedFromLive: %s\n", err)
//}
s.logger.Printf("Inplay match (%s - %s) not found in 1xbet live matches. Remove from inplay\n",
match.Home.CanonicalName, match.Away.CanonicalName)
s.removeMatchFromInplay(match, onexbetMatchID)
} else {
if !watchingMap[onexbetMatchID] {
// Матч есть в лайве 1xbet (liveMap) - но нет в наблюдаемых. Например,
// перезагрузился 1xbet демон, или отписались.
if len(match.Strategies) > 0 {
// Если еще есть не сработавшие стратегии - начинаем наблюдать.
//s.logger.Printf("Watch: %d, %s\n", in.SportID, onexbetMatchID)
// Подписываемся на матчи, которые только что идентифицировали + на те, которые
// пропали из watch списка (например из-за перезагрузки 1xBET демона)
for _, strategy := range match.Strategies {
if strategy.IsNeedToWatch(liveMatch) {
// Если хотя бы одной стратегии нужно наблюдать за матчем
// - подписываемся и прерываем цикл
match.IsInplay = true
s.onexbetAPIClient.Call(api.CallReq{
FuncName: "watch",
In: onexbet.WatchReq{
SportID: onexbetSportID,
MatchID: onexbetMatchID,
},
})
s.mutex.Lock()
// Матч дабавили в inplay
s.publisher.Publish(
getChannel(match.SportID),
WSMessageInplayStatusChanged,
InplayStatusMessage{
MatchID: match.MatchID,
IsInplay: match.IsInplay,
IsLinkedToOnexbet: match.IsLinkedToOnexbet,
},
)
s.mutex.Unlock()
// ВАЖНО!
break
}
}
} else {
s.mutex.Lock()
//s.logger.Printf("Unwatch: %d, %s\n", in.SportID, onexbetMatchID)
// Матч больше не интересен
// Все стратегии сработали - отписываемся от матча
delete(s.onexbetMatchToTeamMatch, onexbetMatchID)
match.IsInplay = false
s.onexbetAPIClient.Call(api.CallReq{
FuncName: "unwatch",
In: onexbet.WatchReq{
SportID: onexbetSportID,
MatchID: onexbetMatchID,
},
})
// Матч убрали из inplay
s.publisher.Publish(
getChannel(match.SportID),
WSMessageInplayStatusChanged,
InplayStatusMessage{
MatchID: match.MatchID,
IsInplay: match.IsInplay,
IsLinkedToOnexbet: match.IsLinkedToOnexbet,
},
)
s.mutex.Unlock()
}
} else {
// Матч есть в лайве 1xbet (liveMap) и в наблюдаемых - все OK.
// Ничего не делаем.
}
}
}
}
/*
func (s *Daemon) processMatchDisappearedFromLive(match *TeamMatch, onexbetMatchID string) (err error) {
if match.OnexbetStatsMatchID == "" {
// Ситуация возвожна, когда матч появился на короткий срок, OnexbetStatsMatchID еще
// не получил и затем исчез.
err = fmt.Errorf("1xBet match %s has empty OnexbetStatsMatchID", onexbetMatchID)
return
}
matchResult, err := onexbet.GetTeamMatchResult(match.OnexbetStatsMatchID)
if err != nil {
err = fmt.Errorf("onexbet.GetTeamMatchResult: %s", err)
return
}
if matchResult.Status != onexbet.StatusMatchCompleted {
// Если матч не завершен - пропускаем. Предполагаем что матч просто
// временно исчез из лайва
return
}
// Матч завершен - загружаем прогнозы, чтобы выставить результаты
tips, err := s.model.ListMatchTips(match.MatchID)
if err != nil {
err = fmt.Errorf("model.ListMatchTips: %s; matchID=%s", err, match.MatchID)
return
}
if len(tips) > 0 {
// На один матч может быть несколько прогнозов, поэтому важно знать что результаты
// всех прогнозов удалось записать в БД. Пока все результаты записать не удастся -
// это метод будет вызыватся снова и снова.
for _, tip := range tips {
err = s.trySetTipResult(tip, matchResult)
if err != nil {
err = fmt.Errorf("trySetTipResult: %s; tipID=%d", err, tip.TipID)
return
}
}
}
// Результат всех прогнозов по матчу успешно записан либо прогнозов не было.
// В любом случае - удаляем матч из лайва.
s.removeMatchFromInplay(match, onexbetMatchID)
return
}
*/
func (s *Daemon) removeMatchFromInplay(match *TeamMatch, onexbetMatchID string) {
s.mutex.Lock()
defer s.mutex.Unlock()
delete(s.onexbetMatchToTeamMatch, onexbetMatchID)
match.IsInplay = false
// Матч убрали из inplay
s.publisher.Publish(
getChannel(match.SportID),
WSMessageInplayStatusChanged,
InplayStatusMessage{
MatchID: match.MatchID,
IsInplay: match.IsInplay,
IsLinkedToOnexbet: match.IsLinkedToOnexbet,
},
)
}
type WhyNot struct {
MatchID string `json:"matchID"`
Comment string `json:"comment"`
Time string `json:"time"`
HomeGoals int `json:"homeGoals"`
AwayGoals int `json:"awayGoals"`
GamePace float64 `json:"gamePace"`
GamePaceFrame int `json:"gamePaceFrame"` // count from Zero
}
//func (s *Daemon) onOnexbetTennisLiveMatchData(conn *ws.Conn, upd onexbet.TeamLiveMatchData) {
// s.mutex.Lock()
// defer s.mutex.Unlock()
// s.logger.Printf("tennis MatchData: %s\n", upd.MatchID)
//}
/*
type TeamLiveMatchData struct {
MatchID string `json:"matchID"`
HomeAttacks int `json:"homeAttacks"`
HomeDangerousAttacks int `json:"homeDangerousAttacks"`
HomeShotsOnTarget int `json:"homeShotsOnTarget"`
HomeShotsOffTarget int `json:"homeShotsOffTarget"`
AwayAttacks int `json:"awayAttacks"`
AwayDangerousAttacks int `json:"awayDangerousAttacks"`
AwayShotsOnTarget int `json:"awayShotsOnTarget"`
AwayShotsOffTarget int `json:"awayShotsOffTarget"`
CurrentTime int `json:"currentTime"`
HomeGoals int `json:"homeGoals"`
AwayGoals int `json:"awayGoals"`
Winner *Winner3Way `json:"winner"`
Total Total `json:"total"`
Handicap Handicap `json:"handicap"`
IndividualTotalHome Total `json:"individualTotalHome"`
IndividualTotalAway Total `json:"individualTotalAway"`
H1 Half `json:"h1"` // 1st half
// tennis
Winner2Way *Winner2Way `json:"winner2way"`
// score
Score Score `json:"score"`
ScoreByPeriods map[int]Score `json:"scoreByPeriods"`
CurrentPeriod int `json:"currentPeriod"`
Periods map[int]Period `json:"periods"`
}
*/
func swapTeamLiveMatchData(d onexbet.TeamLiveMatchData) onexbet.TeamLiveMatchData {
d.AwayAttacks, d.HomeAttacks = d.HomeAttacks, d.AwayAttacks
d.AwayDangerousAttacks, d.HomeDangerousAttacks = d.HomeDangerousAttacks, d.AwayDangerousAttacks
d.AwayShotsOnTarget, d.HomeShotsOnTarget = d.HomeShotsOnTarget, d.AwayShotsOnTarget
d.AwayShotsOffTarget, d.HomeShotsOffTarget = d.HomeShotsOffTarget, d.AwayShotsOffTarget
d.AwayGoals, d.HomeGoals = d.HomeGoals, d.AwayGoals
if d.Winner != nil {
d.Winner.Away, d.Winner.Home = d.Winner.Home, d.Winner.Away
}
if d.Winner2Way != nil {
d.Winner2Way.Away, d.Winner2Way.Home = d.Winner2Way.Home, d.Winner2Way.Away
}
d.Handicap.Away, d.Handicap.Home = d.Handicap.Home, d.Handicap.Away
d.IndividualTotalAway, d.IndividualTotalHome = d.IndividualTotalHome, d.IndividualTotalAway
d.H1.IndividualTotalAway, d.H1.IndividualTotalHome = d.H1.IndividualTotalHome, d.H1.IndividualTotalAway
d.Score.Away, d.Score.Home = d.Score.Home, d.Score.Away
for periodNumber, score := range d.ScoreByPeriods {
score.Away, score.Home = score.Home, score.Away
d.ScoreByPeriods[periodNumber] = score
}
for periodNumber, period := range d.Periods {
period.Handicap.Away, period.Handicap.Home = period.Handicap.Home, period.Handicap.Away
d.Periods[periodNumber] = period
}
return d
}
func (s *Daemon) onOnexbetTeamLiveMatchData(conn *ws.Conn, upd onexbet.TeamLiveMatchData) {
s.mutex.Lock()
defer s.mutex.Unlock()
s.logger.Printf("MatchData: %s\n", upd.MatchID)
// маппинг -
match, ok := s.onexbetMatchToTeamMatch[upd.MatchID]
if !ok {
return
}
if match.IsTeamsSwapped {
upd = swapTeamLiveMatchData(upd)
}
//if match.SportID == flashscore.Handball {
//x, _ := json.MarshalIndent(upd, "", " ")
//fmt.Printf("MatchID: %s (1xbet MatchID: %s), Time: %d, HomeGoals: %d, AwayGoals: %d\n",
// match.MatchID, upd.MatchID, upd.CurrentTime, upd.HomeGoals, upd.AwayGoals)
//}
channel := getChannel(match.SportID)
//s.logger.Printf("Onexbet TeamLiveMatchData: sportID %d, channel %s\n", match.SportID, channel)
var (
triggeredStrategyIDs []int64
comments []string
strategyIDs []int
)
for strategyID := range match.Strategies {
strategyIDs = append(strategyIDs, int(strategyID))
}
sort.Ints(strategyIDs)
for _, strategyID := range strategyIDs {
strategy := match.Strategies[int64(strategyID)]
// Если по стратегии уже дали прогноз
//if match.EndedStrategies[strategy.ID()] {
// continue
//}
whyNot, bet, code := strategy.GetTip(match, upd)
switch code {
case Waiting:
// pass
//s.logger.Printf("Waiting: %s\n", whyNot)
// Отправить в websocket
comments = append(comments, fmt.Sprintf("%s:<br>%s", strategy.ShortName(), whyNot))
case Unwatch:
s.logger.Printf("Unwatch: %s\n", whyNot)
triggeredStrategyIDs = append(triggeredStrategyIDs, strategy.ID())
comments = append(comments, fmt.Sprintf("%s:<br>%s", strategy.ShortName(), whyNot))
case Bet:
triggeredStrategyIDs = append(triggeredStrategyIDs, strategy.ID())
var err error
//var tip model.Tip
//var tipPrice float64
tip := model.Tip{
SportID: int64(match.SportID),
StrategyID: strategy.ID(),
MatchID: match.MatchID,
TipTime: time.Now().Unix(),
ChampID: match.Champ.ChampID,
ChampName: match.Champ.Name,
MatchName: fmt.Sprintf("%s - %s", match.Home.CanonicalName, match.Away.CanonicalName),
Market: bet.Market,
Side: bet.Side,
Param: bet.Param,
Price: bet.Price,
CurrentMatchTime: upd.CurrentTime,
OnexbetStatsMatchID: match.OnexbetStatsMatchID,
IsTeamsSwapped: match.IsTeamsSwapped,
}
champRatings, ok := s.champRatings[match.SportID]
if ok {
// обновляем рейтинги чемпионатов
key := ChampRatingKey{
ChampID: tip.ChampID,
StrategyID: tip.StrategyID,
}
rating, ok := champRatings[key]
if ok {
//if (rating.Won+rating.Lost) >= 6 && rating.GetAccuracy() >= 75 {
if rating.GetAccuracy() >= 70 {
tip.IsRated = true
}
}
}
s.logger.Printf("Bet: %#v\n", tip)
tip.TipID, err = s.model.AddTip(tip)
if err != nil {
s.logger.Printf("model.AddTip: %s\n", err)
} else {
// Отправить в websocket
// Добавили новый Tip
s.publisher.Publish(channel, WSMessageTipsChanged, nil)
if match.SportID == flashscore.Football {
// Для футбола только рейтинговые чемпионаты
// Отправить в телеграм
if strategy.IsNotifyInTelegram() && tip.IsRated {
// Отправлять ли в телеграм
msg := fmt.Sprintf(strategy.GetTelegramTipPattern(), tip.TipID, strategy.ID(),
match.Zone.Name, match.Champ.Name,
match.Home.CanonicalName, match.Away.CanonicalName,
bet.Price)
telegramChatID, hasChat := sportToTelegramChatID[match.SportID]
if hasChat {
err = sendMessageToTelegramGroup(telegramChatID, msg)
if err != nil {
s.logger.Printf("send tip to Telegram: %s\n", err)
}
} else {
s.logger.Printf("Sport %d hasn't telegram chat\n", match.SportID)
}
}
} else if match.SportID == flashscore.Handball {
if strategy.IsNotifyInTelegram() && tip.IsRated {
param, err := strconv.ParseFloat(bet.Param, 64)
if err != nil {
s.logger.Printf("Wrong bet param: %s; param=%s\n", err, bet.Param)
} else {
var betterParam1, betterParam2 float64
switch strategy.(type) {
case HandballFTOver, HandballP1Over:
betterParam1 = param - 1
betterParam2 = param - 2
case HandballFTUnder, HandballP1Under:
betterParam1 = param + 1
betterParam2 = param + 2
default:
panic(fmt.Sprintf("Unknown strategy %#v\n", strategy))
}
// Для гандбола отправляем все прогнозы
msg := fmt.Sprintf(strategy.GetTelegramTipPattern(), tip.TipID, strategy.ID(),
match.Zone.Name, match.Champ.Name,
match.Home.CanonicalName, match.Away.CanonicalName,
param, bet.Price, param, betterParam1, betterParam2)
telegramChatID, hasChat := sportToTelegramChatID[match.SportID]
if hasChat {
err = sendMessageToTelegramGroup(telegramChatID, msg)
if err != nil {
s.logger.Printf("send tip to Telegram: %s\n", err)
}
} else {
s.logger.Printf("Sport %d hasn't telegram chat\n", match.SportID)
}
}
}
} else if match.SportID == flashscore.Tennis {
if strategy.IsNotifyInTelegram() {
msg := fmt.Sprintf(bet.TelegramMessage, tip.TipID)
telegramChatID, hasChat := sportToTelegramChatID[match.SportID]
if hasChat {
err = sendMessageToTelegramGroup(telegramChatID, msg)
if err != nil {
s.logger.Printf("send tip to Telegram: %s\n", err)
}
} else {
s.logger.Printf("Sport %d hasn't telegram chat\n", match.SportID)
}
}
}
}
}
}
for _, strategyID := range triggeredStrategyIDs {
delete(match.Strategies, strategyID)
}
if len(match.Strategies) == 0 {
// Все стратегии сработали - отписываемся от матча
s.logger.Printf("Unwatch: %d, %s\n", match.SportID, upd.MatchID)
// Матч больше не интересен
delete(s.onexbetMatchToTeamMatch, upd.MatchID)
match.IsInplay = false
s.onexbetAPIClient.Call(api.CallReq{
FuncName: "unwatch",
In: onexbet.WatchReq{
SportID: flashscoreSportToOnexbetSport[match.SportID],
MatchID: upd.MatchID, // onexbetMatchID
},
})
}
if match.SportID == flashscore.Tennis {
if len(comments) > 0 {
s.publisher.Publish(
channel,
WSMessageWhyNot,
WhyNot{
MatchID: match.MatchID,
Comment: strings.Join(comments, "<br><br>"),
Time: "",
HomeGoals: upd.HomeGoals,
AwayGoals: upd.AwayGoals,
GamePace: match.GamePace,
GamePaceFrame: match.GamePaceFrame,
})
}
} else {
if len(comments) > 0 {
s.publisher.Publish(
channel,
WSMessageWhyNot,
WhyNot{
MatchID: match.MatchID,
Comment: strings.Join(comments, "<br><br>"),
Time: fmt.Sprintf("%s", time.Duration(upd.CurrentTime)*time.Second),
HomeGoals: upd.HomeGoals,
AwayGoals: upd.AwayGoals,
GamePace: match.GamePace,
GamePaceFrame: match.GamePaceFrame,
})
}
}
}
/*
var tipTextPattern string
switch strategyID {
case 1:
tipTextPattern = tipTextAlgo1Pattern
case 2:
tipTextPattern = tipTextAlgo2Pattern
case 3:
tipTextPattern = tipTextAlgo3Pattern
case 100:
tipTextPattern = tipTextAlgo100Pattern
}
*/
/*
switch strategyID {
case 1:
var price float64
for _, over := range upd.H1.Total.Over {
if over.Param == "0.5" {
price = over.Price
}
}
tipPrice = price
tip = model.Tip{
SportID: SportFootball,
StrategyID: int64(strategyID),
MatchID: match.MatchID,
TipTime: time.Now().Unix(),
ChampName: match.Champ.Name,
MatchName: fmt.Sprintf("%s - %s", match.Home.CanonicalName, match.Away.CanonicalName),
Market: MarketTotal1stHalf,
Side: SideOver,
Param: "0.5",
Price: price,
CurrentMatchTime: upd.CurrentTime,
OnexbetStatsMatchID: match.OnexbetStatsMatchID,
}
case 2:
var price float64
for _, over := range upd.Total.Over {
if over.Param == "0.5" {
price = over.Price
}
}
tipPrice = price
tip = model.Tip{
SportID: SportFootball,
StrategyID: int64(strategyID),
MatchID: match.MatchID,
TipTime: time.Now().Unix(),
ChampName: match.Champ.Name,
MatchName: fmt.Sprintf("%s - %s", match.Home.CanonicalName, match.Away.CanonicalName),
Market: MarketTotal,
Side: SideOver,
Param: "0.5",
Price: price,
CurrentMatchTime: upd.CurrentTime,
OnexbetStatsMatchID: match.OnexbetStatsMatchID,
}
case 3:
var price float64
for _, over := range upd.Total.Over {
if over.Param == "1.5" {
price = over.Price
}
}
tipPrice = price
tip = model.Tip{
SportID: SportFootball,
StrategyID: int64(strategyID),
MatchID: match.MatchID,
TipTime: time.Now().Unix(),
ChampName: match.Champ.Name,
MatchName: fmt.Sprintf("%s - %s", match.Home.CanonicalName, match.Away.CanonicalName),
Market: MarketTotal,
Side: SideOver,
Param: "1.5",
Price: price,
CurrentMatchTime: upd.CurrentTime,
OnexbetStatsMatchID: match.OnexbetStatsMatchID,
}
case 100:
var price float64
for _, over := range upd.H1.Total.Over {
if over.Param == "0.5" {
price = over.Price
}
}
tipPrice = price
tip = model.Tip{
SportID: SportFootball,
StrategyID: int64(strategyID),
MatchID: match.MatchID,
TipTime: time.Now().Unix(),
ChampName: match.Champ.Name,
MatchName: fmt.Sprintf("%s - %s", match.Home.CanonicalName, match.Away.CanonicalName),
Market: MarketTotal1stHalf,
Side: SideOver,
Param: "0.5",
Price: price,
CurrentMatchTime: upd.CurrentTime,
OnexbetStatsMatchID: match.OnexbetStatsMatchID,
}
}
*/