Refactoring codes for more tg message types

This commit is contained in:
2026-03-07 22:16:14 +08:00
parent a396a381b5
commit 912f9fd0ad
26 changed files with 771 additions and 472 deletions

View File

@@ -12,7 +12,8 @@ type CChar struct {
JyutPing *CJyutPing
DukJam *[]*DukJam
_JiDukJam *[]*CJyutPing
query.Searchable
query.Words
query.NoGeoLocation
}
type DukJam struct {
@@ -25,7 +26,8 @@ type CJyutPing struct {
SearchKey string // Searchable key
TungJamZi *[]*CChar
tSorted bool
query.Searchable
query.Words
query.NoGeoLocation
}
func (this *CJyutPing) Test(val string) bool {

View File

@@ -13,6 +13,9 @@ type QueryResult struct {
Lang string
Error error
Query *query.QueryObject
ResultType string
isConsumed bool
}
func writeCCharInfo(sb *strings.Builder, cc *CChar) {
@@ -37,14 +40,20 @@ func writeCCharInfo(sb *strings.Builder, cc *CChar) {
}
}
func (this QueryResult) DataType() string { return this.ResultType }
func (this QueryResult) Consumed() bool { return this.isConsumed }
func (this QueryResult) GetTableData() [][]map[string]string { return nil }
func (this QueryResult) Message() (string, error) {
this.ResultType = "PlainText"
if this.Error != nil {
return "", this.Error
}
if this.Query == nil {
panic("Query is nil")
return "", nil
}
sb := strings.Builder{}

View File

@@ -1,13 +1,16 @@
package cjlookup
import (
"fmt"
"strings"
"github.com/tgckpg/golifehk/query"
)
func Query(lang string, message string) query.IQueryResult {
func Query(q query.QueryMessage) query.IQueryResult {
lang := q.Lang
message := q.Text
var qResults *query.QueryObject
var err error
var searchables *[]query.ISearchable
@@ -17,9 +20,12 @@ func Query(lang string, message string) query.IQueryResult {
// Only look up jyut ping
if !strings.HasPrefix(messageU, "JP ") {
err = fmt.Errorf("Invalid query")
qr.ResultType = "IGNORE"
goto qrReturn
}
qr.isConsumed = true
if err != nil {
qr.Error = err
goto qrReturn
@@ -28,7 +34,7 @@ func Query(lang string, message string) query.IQueryResult {
messageU = messageU[3:]
searchables, err = getSearchables()
qResults, err = query.Parse(messageU, searchables)
qResults, err = query.MatchKeys(messageU, searchables)
qr.Query = qResults

View File

@@ -1,176 +1,181 @@
package kmb
import (
"fmt"
"sort"
"strings"
"time"
"fmt"
"sort"
"strings"
"time"
query "github.com/tgckpg/golifehk/query"
utils "github.com/tgckpg/golifehk/utils"
query "github.com/tgckpg/golifehk/query"
utils "github.com/tgckpg/golifehk/utils"
)
type QueryResult struct {
Schedules *map[*RouteStop] *[] *Schedule
Lang string
Error error
Query *query.QueryObject
Schedules *map[*RouteStop]*[]*Schedule
Lang string
Error error
Query *query.QueryObject
isConsumed bool
}
func writeRouteHead( sb *strings.Builder, r *RouteStop ) {
utils.WriteMDv2Text( sb, r.RouteId )
if r.Direction == "O" {
sb.WriteString( "↑" )
} else if r.Direction == "I" {
sb.WriteString( "↓" )
}
if r.ServiceType != "1" {
utils.WriteMDv2Text( sb, utils.ToPower( r.ServiceType ) )
}
func writeRouteHead(sb *strings.Builder, r *RouteStop) {
utils.WriteMDv2Text(sb, r.RouteId)
if r.Direction == "O" {
sb.WriteString("↑")
} else if r.Direction == "I" {
sb.WriteString("↓")
}
if r.ServiceType != "1" {
utils.WriteMDv2Text(sb, utils.ToPower(r.ServiceType))
}
}
func writeShortRoute( lang *string, sb *strings.Builder, r *RouteStop ) {
func writeShortRoute(lang *string, sb *strings.Builder, r *RouteStop) {
if r.PrevStop() != nil {
utils.WriteMDv2Text( sb, (*(r.PrevStop().BusStop).Name)[ *lang ] )
sb.WriteString( " \\> " )
}
if r.PrevStop() != nil {
utils.WriteMDv2Text(sb, (*(r.PrevStop().BusStop).Name)[*lang])
sb.WriteString(" \\> ")
}
sb.WriteString( "*" )
utils.WriteMDv2Text( sb, (*(r.BusStop).Name)[ *lang ] )
sb.WriteString( "*" )
sb.WriteString("*")
utils.WriteMDv2Text(sb, (*(r.BusStop).Name)[*lang])
sb.WriteString("*")
if r.NextStop() != nil {
sb.WriteString( " \\> " )
utils.WriteMDv2Text( sb, (*(r.NextStop().BusStop).Name)[ *lang ] )
}
if r.NextStop() != nil {
sb.WriteString(" \\> ")
utils.WriteMDv2Text(sb, (*(r.NextStop().BusStop).Name)[*lang])
}
sb.WriteString( "\n" )
sb.WriteString("\n")
}
func ( this *QueryResult ) Message() ( string, error ) {
func (this QueryResult) DataType() string { return "MarkdownV2" }
func (this QueryResult) Consumed() bool { return this.isConsumed }
func (this QueryResult) GetTableData() [][]map[string]string { return nil }
if this.Error != nil {
return "", this.Error
}
func (this *QueryResult) Message() (string, error) {
sb := strings.Builder{}
if this.Error != nil {
return "", this.Error
}
if 0 < len( *this.Query.Results ) {
sb := strings.Builder{}
// Print Stop Names, then print the list of routes
if this.Query.Key == "" {
busStops := map[string] *BusStop{}
for _, item := range *this.Query.Results {
var r *RouteStop
r = any( item ).( *RouteStop )
if 0 < len(*this.Query.Results) {
b := r.BusStop
if b.Routes == nil {
continue
}
// Print Stop Names, then print the list of routes
if this.Query.Key == "" {
busStops := map[string]*BusStop{}
for _, item := range *this.Query.Results {
var r *RouteStop
r = any(item).(*RouteStop)
busStops[ b.BusStopId ] = b
}
b := r.BusStop
if b.Routes == nil {
continue
}
for _, b := range busStops {
utils.WriteMDv2Text( &sb, (*b.Name)[ this.Lang ] )
sb.WriteString( "\n " )
for _, route := range *b.Routes {
writeRouteHead( &sb, route )
sb.WriteString( " " )
}
sb.WriteString( "\n" )
}
busStops[b.BusStopId] = b
}
// We got a route key
} else {
for _, b := range busStops {
utils.WriteMDv2Text(&sb, (*b.Name)[this.Lang])
sb.WriteString("\n ")
for _, route := range *b.Routes {
writeRouteHead(&sb, route)
sb.WriteString(" ")
}
sb.WriteString("\n")
}
// We also got other search keys with 1 < Results
// Get the ETA for this stop
if 1 < len( *this.Query.SearchTerms ) {
// We got a route key
} else {
now := time.Now()
for _, item := range *this.Query.Results {
var r *RouteStop
r = any( item ).( *RouteStop )
writeRouteHead( &sb, r )
sb.WriteString( "\n" )
writeShortRoute( &this.Lang, &sb, r )
// We also got other search keys with 1 < Results
// Get the ETA for this stop
if 1 < len(*this.Query.SearchTerms) {
for _, schedule := range *(*this.Schedules)[ r ] {
now := time.Now()
for _, item := range *this.Query.Results {
var r *RouteStop
r = any(item).(*RouteStop)
writeRouteHead(&sb, r)
sb.WriteString("\n")
writeShortRoute(&this.Lang, &sb, r)
if !schedule.ETA.IsZero() {
for _, schedule := range *(*this.Schedules)[r] {
_m := schedule.ETA.Sub( now ).Minutes()
if !schedule.ETA.IsZero() {
sb.WriteString( " \\* " )
txt := "%.0f min(s)"
_m := schedule.ETA.Sub(now).Minutes()
if this.Lang == "zh-Hant" {
txt = "%.0f 分鐘"
}
sb.WriteString(" \\* ")
txt := "%.0f min(s)"
utils.WriteMDv2Text( &sb, fmt.Sprintf( txt, _m ) )
if this.Lang == "zh-Hant" {
txt = "%.0f 分鐘"
}
if _m < 0 {
sb.WriteString( " 走左了?" )
}
}
utils.WriteMDv2Text(&sb, fmt.Sprintf(txt, _m))
if schedule.Remarks_en != "" {
sb.WriteString( " \\*\\* " )
switch this.Lang {
case "en":
utils.WriteMDv2Text( &sb, schedule.Remarks_en )
case "zh-Hant":
utils.WriteMDv2Text( &sb, schedule.Remarks_tc )
}
}
if _m < 0 {
sb.WriteString(" 走左了?")
}
}
sb.WriteString( "\n" )
}
if schedule.Remarks_en != "" {
sb.WriteString(" \\*\\* ")
switch this.Lang {
case "en":
utils.WriteMDv2Text(&sb, schedule.Remarks_en)
case "zh-Hant":
utils.WriteMDv2Text(&sb, schedule.Remarks_tc)
}
}
sb.WriteString( "\n" )
}
sb.WriteString("\n")
}
// We got only the route key, proceed to list the route stops
} else {
// Result contains all route stops, we only need the starting one
routes := [] *RouteStop{}
sb.WriteString("\n")
}
for _, item := range *this.Query.Results {
var r *RouteStop
r = any( item ).( *RouteStop )
if r.PrevStop() == nil {
routes = append( routes, r )
}
}
// We got only the route key, proceed to list the route stops
} else {
// Result contains all route stops, we only need the starting one
routes := []*RouteStop{}
sort.Sort( ByRoute( routes ) )
for _, item := range *this.Query.Results {
var r *RouteStop
r = any(item).(*RouteStop)
if r.PrevStop() == nil {
routes = append(routes, r)
}
}
for _, r := range routes {
writeRouteHead( &sb, r )
sb.WriteString( "\n" )
for {
b := *r.BusStop
utils.WriteMDv2Text( &sb, (*b.Name)[ this.Lang ] )
r = r.NextStop()
if r == nil {
break
}
sort.Sort(ByRoute(routes))
sb.WriteString( " \\> " )
}
sb.WriteString( "\n" )
}
for _, r := range routes {
writeRouteHead(&sb, r)
sb.WriteString("\n")
for {
b := *r.BusStop
utils.WriteMDv2Text(&sb, (*b.Name)[this.Lang])
r = r.NextStop()
if r == nil {
break
}
sb.WriteString(" \\> ")
}
sb.WriteString("\n")
}
}
}
} else {
return "", fmt.Errorf( "No Results" )
}
}
}
} else {
return "", fmt.Errorf("No Results")
}
return sb.String(), nil
return sb.String(), nil
}

View File

@@ -1,65 +1,66 @@
package kmb
import (
query "github.com/tgckpg/golifehk/query"
query "github.com/tgckpg/golifehk/query"
)
type RouteStop struct {
BusStop *BusStop
RouteId string `json:"route"`
ServiceType string `json:"service_type"`
Direction string `json:"bound"`
StationSeq int `json:"seq,string"`
StationId string `json:"stop"`
BusStop *BusStop
RouteId string `json:"route"`
ServiceType string `json:"service_type"`
Direction string `json:"bound"`
StationSeq int `json:"seq,string"`
StationId string `json:"stop"`
RouteStops *map[int] *RouteStop
query.Searchable
RouteStops *map[int]*RouteStop
query.Words
query.NoGeoLocation
}
type RouteStops struct {
Type string `json:"type"`
Version string `json:"version"`
DateCreated string `json:"generated_timestamp"`
RouteStops [] *RouteStop `json:"data"`
Type string `json:"type"`
Version string `json:"version"`
DateCreated string `json:"generated_timestamp"`
RouteStops []*RouteStop `json:"data"`
}
func ( routeStop RouteStop ) PrevStop() *RouteStop {
if v, hasKey := (*routeStop.RouteStops)[ routeStop.StationSeq - 1 ]; hasKey {
return v
}
return nil
func (routeStop RouteStop) PrevStop() *RouteStop {
if v, hasKey := (*routeStop.RouteStops)[routeStop.StationSeq-1]; hasKey {
return v
}
return nil
}
func ( routeStop RouteStop ) NextStop() *RouteStop {
if v, hasKey := (*routeStop.RouteStops)[ routeStop.StationSeq + 1 ]; hasKey {
return v
}
return nil
func (routeStop RouteStop) NextStop() *RouteStop {
if v, hasKey := (*routeStop.RouteStops)[routeStop.StationSeq+1]; hasKey {
return v
}
return nil
}
func ( this *RouteStop ) Reload() {
func (this *RouteStop) Reload() {
searchData := [] *string{}
busStop := *this.BusStop
searchData = append( searchData, &busStop.Name_en )
searchData = append( searchData, &busStop.Name_tc )
searchData := []*string{}
busStop := *this.BusStop
searchData = append(searchData, &busStop.Name_en)
searchData = append(searchData, &busStop.Name_tc)
this.Key = &this.RouteId
this.SearchData = &searchData
this.Key = &this.RouteId
this.SearchData = &searchData
}
type ByRoute [] *RouteStop
type ByRoute []*RouteStop
func (a ByRoute) Len() int { return len(a) }
func (a ByRoute) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByRoute) Len() int { return len(a) }
func (a ByRoute) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByRoute) Less(i, j int) bool {
_a := *a[i]
_b := *a[j]
if _a.RouteId == _b.RouteId {
if _a.Direction == _b.Direction {
return _a.ServiceType < _b.ServiceType
}
return _a.Direction < _b.Direction
}
return _a.RouteId < _b.RouteId
_a := *a[i]
_b := *a[j]
if _a.RouteId == _b.RouteId {
if _a.Direction == _b.Direction {
return _a.ServiceType < _b.ServiceType
}
return _a.Direction < _b.Direction
}
return _a.RouteId < _b.RouteId
}

View File

@@ -6,7 +6,10 @@ import (
"strings"
)
func Query(lang string, message string) query.IQueryResult {
func Query(q query.QueryMessage) query.IQueryResult {
lang := q.Lang
message := q.Text
var qo *query.QueryObject
var err error
@@ -18,7 +21,7 @@ func Query(lang string, message string) query.IQueryResult {
goto qrReturn
}
qo, err = query.Parse(strings.ToUpper(message), routeStops)
qo, err = query.MatchKeys(strings.ToUpper(message), routeStops)
if err != nil {
qr.Error = err
goto qrReturn

View File

@@ -2,6 +2,7 @@ package bus
import (
i18n "github.com/tgckpg/golifehk/i18n"
query "github.com/tgckpg/golifehk/query"
)
type BusStop struct {
@@ -10,8 +11,6 @@ type BusStop struct {
Direction string
StationSeq int
StationId string
Latitude float64
Longtitude float64
Name_zh string
Name_en string
@@ -22,6 +21,7 @@ type BusStop struct {
AltRoutes *map[string]*BusStop
i18n.Generics
query.GeoLocation
}
func (this *BusStop) PrevStop() *BusStop {
@@ -52,6 +52,14 @@ func (this *BusStop) Reload() {
this.SearchData = &searchData
}
func (this BusStop) Register(registers map[string]struct{}) bool {
if _, ok := registers[this.StationId]; ok {
return false
}
registers[this.StationId] = struct{}{}
return true
}
type ByRoute []*BusStop
func (a ByRoute) Len() int { return len(a) }

View File

@@ -14,7 +14,10 @@ type QueryResult struct {
Schedules *map[*BusStop]*BusStopBuses
Lang string
Error error
Source *query.QueryMessage
Query *query.QueryObject
isConsumed bool
}
func writeShortRoute(lang *string, sb *strings.Builder, b *BusStop) {
@@ -35,6 +38,10 @@ func writeShortRoute(lang *string, sb *strings.Builder, b *BusStop) {
sb.WriteString("\n")
}
func (this QueryResult) DataType() string { return "MarkdownV2" }
func (this QueryResult) Consumed() bool { return this.isConsumed }
func (this QueryResult) GetTableData() [][]map[string]string { return nil }
func (this QueryResult) Message() (string, error) {
if this.Error != nil {
@@ -56,12 +63,41 @@ func (this QueryResult) Message() (string, error) {
}
if q.Key == "" {
sort.Sort(query.ByKey(*q.Results))
for _, entry := range *q.Results {
busStop := any(entry).(*BusStop)
utils.WriteMDv2Text(&sb, busStop.RouteId)
sb.WriteString(" ")
writeShortRoute(&this.Lang, &sb, busStop)
loc := q.Message.Location
if loc != nil {
// Print nearest bus stops
for _, entry := range *q.Results {
busStop := any(entry).(*BusStop)
utils.WriteMDv2Text(&sb, fmt.Sprintf("%.2fm", busStop.Dist(loc.Lat(), loc.Lon())))
sb.WriteString(" ")
sb.WriteString(" [")
utils.WriteMDv2Text(&sb, busStop.RouteId)
d := busStop.Direction
if d == "O" {
sb.WriteString("↑")
} else if d == "I" {
sb.WriteString("↓")
} else {
sb.WriteString("\\?")
}
utils.WriteMDv2Text(&sb, (*busStop.Name)[this.Lang])
utils.WriteMDv2Text(&sb, busStop.RouteId)
utils.WriteMDv2Text(&sb, (*busStop.Name)[this.Lang])
sb.WriteString(")")
sb.WriteString("\n")
}
} else {
sort.Sort(query.ByKey(*q.Results))
for _, entry := range *q.Results {
busStop := any(entry).(*BusStop)
utils.WriteMDv2Text(&sb, busStop.RouteId)
sb.WriteString(" ")
writeShortRoute(&this.Lang, &sb, busStop)
}
}
} else if 1 == len(*q.SearchTerms) {

View File

@@ -50,7 +50,7 @@ func readBusStopData(r io.Reader) (*map[string]*BusStop, error) {
entry.Latitude = v
case "STATION_LONGITUDE":
v, _ := strconv.ParseFloat(value, 64)
entry.Longtitude = v
entry.Longitude = v
case "STATION_NAME_CHI":
entry.Name_zh = value
case "STATION_NAME_ENG":

View File

@@ -6,7 +6,9 @@ import (
query "github.com/tgckpg/golifehk/query"
)
func Query(lang string, message string) query.IQueryResult {
func Query(q query.QueryMessage) query.IQueryResult {
lang := q.Lang
var qBusStops *query.QueryObject
var err error
@@ -18,7 +20,14 @@ func Query(lang string, message string) query.IQueryResult {
goto qrReturn
}
qBusStops, err = query.Parse(strings.ToUpper(message), busStops)
if q.Text != "" {
qBusStops, err = query.MatchKeys(strings.ToUpper(q.Text), busStops)
} else if q.Location != nil {
qBusStops, err = query.MatchNearest(*q.Location, busStops, 100, 3)
}
qBusStops.Message = &q
if err != nil {
qr.Error = err
goto qrReturn