Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
ef074b98e5 | |||
72ea3c83a4 | |||
d07031c242 | |||
c6d1e79360 | |||
af9aca41b4 | |||
5b079a5872 | |||
20f24be349 | |||
36e6a0f986 | |||
6f0d84aa87 | |||
a4d4cee6cd | |||
f7be57f9dd | |||
57491651d2 | |||
5ee7a22486 | |||
cfd1bb66bd | |||
6e368518c5 | |||
3e4851555d | |||
5f73c5ab5a | |||
e730068834 | |||
7a43213aa4 | |||
d9db1b406a | |||
2d295bb384 | |||
20b6d055bb | |||
545366564f | |||
aee5d92d8d | |||
756272d064 | |||
dfa0f2daff | |||
124ee61e1d | |||
55f710cbbb | |||
9fe660aa71 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.idea/
|
19
README.md
19
README.md
@ -1,6 +1,25 @@
|
|||||||
# telegram
|
# telegram
|
||||||
|
|
||||||
|
`go2v` — утилита для транслирования кода на Go в V. В текущий момент доступна только старая версия утилиты.
|
||||||
|
|
||||||
|
Для установки `go2v`, нужно клонировать репозиторий в данный момент с ветки `old_implementation` и запустить команду `v run .` для компиляции файлов:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/vlang/go2v.git -b old_implementation
|
||||||
|
cd go2v
|
||||||
|
v run .
|
||||||
|
```
|
||||||
|
|
||||||
|
После установки утилиты, можно использовать go2v для трансляции Go-файлов в V:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
v run . path/to/file.go
|
||||||
|
```
|
||||||
|
|
||||||
|
Транслированный файл будет создан в том же каталоге с именем v.
|
||||||
|
Может потребоваться проверка синтаксиса, так как транслирование может содержать ошибки.
|
||||||
|
|
||||||
|
Дополнительную информацию и документацию можно найти в репозитории [go2v на GitHub](https://github.com/vlang/go2v/tree/old_implementation).
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
|
18
client/client.go
Normal file
18
client/client.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
Messages []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient() *Client {
|
||||||
|
return &Client{
|
||||||
|
Messages: []string{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) SendMessage(msg string) {
|
||||||
|
c.Messages = append(c.Messages, msg)
|
||||||
|
fmt.Println("saved message: ", msg)
|
||||||
|
}
|
11
client/client.v
Normal file
11
client/client.v
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module client
|
||||||
|
|
||||||
|
pub struct Client {
|
||||||
|
pub mut:
|
||||||
|
messages []string
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut c Client) send_message(msg string) {
|
||||||
|
c.messages << msg
|
||||||
|
//println('saved message: ${msg}')
|
||||||
|
}
|
3
go.mod
Normal file
3
go.mod
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module penahub.gitlab.yandexcloud.net/backend/quiz/telegram
|
||||||
|
|
||||||
|
go 1.22.5
|
71
main.go
Normal file
71
main.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/telegram/client"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/telegram/models"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/telegram/respondent"
|
||||||
|
stateManager "penahub.gitlab.yandexcloud.net/backend/quiz/telegram/state_manager"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dataSetMap map[string]models.Question
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
f, err := os.Open("treedata.json")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("err open json file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
values, err := io.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("err read json file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dataSet []models.Question
|
||||||
|
err = json.Unmarshal(values, &dataSet)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("err unmarshall json: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dataSetMap = make(map[string]models.Question)
|
||||||
|
for _, data := range dataSet {
|
||||||
|
dataSetMap[data.Title] = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
|
mockClient := client.NewClient()
|
||||||
|
mockStateManager := stateManager.NewStateManager(stateManager.Deps{
|
||||||
|
Questions: dataSetMap,
|
||||||
|
State: "q00",
|
||||||
|
Client: mockClient,
|
||||||
|
})
|
||||||
|
|
||||||
|
mockRespondent := respondent.NewRespondent(mockStateManager)
|
||||||
|
mockStateManager.SendQuestion()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if _, ok := dataSetMap[mockStateManager.State]; !ok {
|
||||||
|
fmt.Println("state not found")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
mockRespondent.Respond("q00")
|
||||||
|
fmt.Println("respond")
|
||||||
|
}
|
||||||
|
|
||||||
|
for number, msg := range mockClient.Messages {
|
||||||
|
fmt.Println(fmt.Sprintf("message %d: %s", number, msg))
|
||||||
|
}
|
||||||
|
//}
|
||||||
|
|
||||||
|
fmt.Println("Complete")
|
||||||
|
}
|
78
main.v
Normal file
78
main.v
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
module main
|
||||||
|
import json
|
||||||
|
import log
|
||||||
|
import os
|
||||||
|
import client
|
||||||
|
import models
|
||||||
|
import respondent
|
||||||
|
import state_manager
|
||||||
|
import our_benchmark
|
||||||
|
import tg_handle
|
||||||
|
import time
|
||||||
|
|
||||||
|
//v -enable-globals run main.v
|
||||||
|
__global (
|
||||||
|
data_set_map map[string]models.Question
|
||||||
|
)
|
||||||
|
|
||||||
|
fn init() {
|
||||||
|
f := os.read_file('treedata.json') or {
|
||||||
|
log.error('err read json file: $err')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data_set := json.decode([]models.Question, f) or {
|
||||||
|
log.error('err unmarshall json: $err')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for data in data_set {
|
||||||
|
data_set_map[data.title] = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mut b := our_benchmark.new_custom_benchmark(test_main,0,0,false) or {
|
||||||
|
eprintln('Error creating benchmark: $err')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b.run_benchmark()
|
||||||
|
|
||||||
|
// mut benchmarks := our_benchmark.InternalBenchmark{
|
||||||
|
// name: 'test_main',
|
||||||
|
// f: test_main,
|
||||||
|
// }
|
||||||
|
// our_benchmark.run_benchmarks(benchmarks)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_main()! {
|
||||||
|
mut mock_client := &client.Client{messages: []string{}}
|
||||||
|
mut mock_state_manager := &state_manager.StateManager{
|
||||||
|
questions: data_set_map
|
||||||
|
state: "q00"
|
||||||
|
client: mock_client
|
||||||
|
}
|
||||||
|
|
||||||
|
// tg_handle.new_tg_bot("6712573453:AAFqTOsgwe_j48ZQ1GzWKQDT5Nwr-SAWjz8")
|
||||||
|
|
||||||
|
mut mock_respondent := respondent.Respondent{manager: mock_state_manager}
|
||||||
|
mock_state_manager.send_question()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if mock_state_manager.state !in data_set_map {
|
||||||
|
//println('state not found')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
mock_respondent.respond("q00")
|
||||||
|
//println('respond')
|
||||||
|
}
|
||||||
|
|
||||||
|
// for number, msg in mock_client.messages {
|
||||||
|
// println('message $number: $msg')
|
||||||
|
// }
|
||||||
|
|
||||||
|
//println('Complete')
|
||||||
|
|
||||||
|
// time.sleep(10 * time.minute)
|
||||||
|
}
|
41
main_test.go
Normal file
41
main_test.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/telegram/client"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/telegram/respondent"
|
||||||
|
stateManager "penahub.gitlab.yandexcloud.net/backend/quiz/telegram/state_manager"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkMain(b *testing.B) {
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
mockClient := client.NewClient()
|
||||||
|
mockStateManager := stateManager.NewStateManager(stateManager.Deps{
|
||||||
|
Questions: dataSetMap,
|
||||||
|
State: "q00",
|
||||||
|
Client: mockClient,
|
||||||
|
})
|
||||||
|
|
||||||
|
mockRespondent := respondent.NewRespondent(mockStateManager)
|
||||||
|
mockStateManager.SendQuestion()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if _, ok := dataSetMap[mockStateManager.State]; !ok {
|
||||||
|
fmt.Println("state not found")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
mockRespondent.Respond("q00")
|
||||||
|
fmt.Println("respond")
|
||||||
|
}
|
||||||
|
|
||||||
|
for number, msg := range mockClient.Messages {
|
||||||
|
fmt.Println(fmt.Sprintf("message %d: %s", number, msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Complete")
|
||||||
|
}
|
||||||
|
}
|
37
main_test.v
Normal file
37
main_test.v
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
module main
|
||||||
|
|
||||||
|
import benchmark
|
||||||
|
import models
|
||||||
|
import respondent
|
||||||
|
import state_manager
|
||||||
|
import client
|
||||||
|
|
||||||
|
fn test_main(){
|
||||||
|
mut bench := benchmark.new_benchmark()
|
||||||
|
for i := 0; i < models.data_set.len; i++ {
|
||||||
|
bench.step()
|
||||||
|
mut mock_client := &client.Client{messages: []string{}}
|
||||||
|
mut mock_state_manager := &state_manager.StateManager{
|
||||||
|
questions: models.data_set[i]
|
||||||
|
state: 'start'
|
||||||
|
client: mock_client
|
||||||
|
}
|
||||||
|
mut mock_respondent := respondent.Respondent{manager: mock_state_manager}
|
||||||
|
mock_state_manager.send_question()
|
||||||
|
for mock_state_manager.state != 'end' {
|
||||||
|
mock_respondent.respond()
|
||||||
|
println('respond')
|
||||||
|
}
|
||||||
|
for number, msg_1 in mock_client.messages {
|
||||||
|
println(' ${'out'} ${i} ${msg_1} ${number}')
|
||||||
|
}
|
||||||
|
bench.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
bench.stop()
|
||||||
|
|
||||||
|
// выводит время
|
||||||
|
bench.measure("test_main")
|
||||||
|
|
||||||
|
println(bench.total_message('remarks about the our_benchmark'))
|
||||||
|
}
|
12
models/models.go
Normal file
12
models/models.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
type Question struct {
|
||||||
|
Title string
|
||||||
|
Description string
|
||||||
|
Buttons []Button
|
||||||
|
}
|
||||||
|
|
||||||
|
type Button struct {
|
||||||
|
Text string
|
||||||
|
State string
|
||||||
|
}
|
16
models/models.v
Normal file
16
models/models.v
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
module models
|
||||||
|
// структуры объявляются в принципе как в гошке, заисключением того что видимо взято из С происходит деление на публичные и приватные
|
||||||
|
// поэтому для того чтобы реализовать инкапсуляцию, если указать ключевое слово pub - будет все доступно
|
||||||
|
|
||||||
|
pub struct Button {
|
||||||
|
pub mut:
|
||||||
|
text string @[json: 'Text']
|
||||||
|
state string @[json: 'State']
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Question {
|
||||||
|
pub mut:
|
||||||
|
title string @[json: 'Title']
|
||||||
|
description string @[json: 'Description']
|
||||||
|
buttons []Button @[json: 'Buttons']
|
||||||
|
}
|
51
models/variants.go
Normal file
51
models/variants.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
var DataSet = []map[string]Question{
|
||||||
|
{
|
||||||
|
"start": {
|
||||||
|
Title: "Start question",
|
||||||
|
Description: "This first question, start",
|
||||||
|
Buttons: []Button{
|
||||||
|
{"start", "q1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"q1": {
|
||||||
|
Title: "Question 1",
|
||||||
|
Description: "This question 1 after start question",
|
||||||
|
Buttons: []Button{
|
||||||
|
{"q2", "q2"},
|
||||||
|
{"q3", "q3"},
|
||||||
|
{"q4", "q4"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"q2": {
|
||||||
|
Title: "Question 2",
|
||||||
|
Description: "This question 2 after question 1",
|
||||||
|
Buttons: []Button{
|
||||||
|
{"Go end", "end"},
|
||||||
|
{"Need end", "end"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"q3": {
|
||||||
|
Title: "Question 3",
|
||||||
|
Description: "This question 3 after question 1",
|
||||||
|
Buttons: []Button{
|
||||||
|
{"Want end", "end"},
|
||||||
|
{"Go dota 2", "end"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"q4": {
|
||||||
|
Title: "Question 4",
|
||||||
|
Description: "This question 4 after question 1",
|
||||||
|
Buttons: []Button{
|
||||||
|
{"Run end", "end"},
|
||||||
|
{"Swimming to end", "end"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
Title: "Last question",
|
||||||
|
Description: "This is last question",
|
||||||
|
Buttons: []Button{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
81
models/variants.v
Normal file
81
models/variants.v
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
module models
|
||||||
|
|
||||||
|
pub const data_set = [
|
||||||
|
{
|
||||||
|
'end': Question{
|
||||||
|
title: 'Last question'
|
||||||
|
description: 'This is last question'
|
||||||
|
buttons: []
|
||||||
|
}
|
||||||
|
'q1': Question{
|
||||||
|
title: 'Question 1'
|
||||||
|
description: 'This question 1 after start question'
|
||||||
|
buttons: [
|
||||||
|
Button{
|
||||||
|
text: 'q2'
|
||||||
|
state: 'q2'
|
||||||
|
},
|
||||||
|
Button{
|
||||||
|
text: 'q3'
|
||||||
|
state: 'q3'
|
||||||
|
},
|
||||||
|
Button{
|
||||||
|
text: 'q4'
|
||||||
|
state: 'q4'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
'q2': Question{
|
||||||
|
title: 'Question 2'
|
||||||
|
description: 'This question 2 after question 1'
|
||||||
|
buttons: [
|
||||||
|
Button{
|
||||||
|
text: 'Go end'
|
||||||
|
state: 'end'
|
||||||
|
},
|
||||||
|
Button{
|
||||||
|
text: 'Need end'
|
||||||
|
state: 'end'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
'q3': Question{
|
||||||
|
title: 'Question 3'
|
||||||
|
description: 'This question 3 after question 1'
|
||||||
|
buttons: [
|
||||||
|
Button{
|
||||||
|
text: 'Want end'
|
||||||
|
state: 'end'
|
||||||
|
},
|
||||||
|
Button{
|
||||||
|
text: 'Go dota 2'
|
||||||
|
state: 'end'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
'q4': Question{
|
||||||
|
title: 'Question 4'
|
||||||
|
description: 'This question 4 after question 1'
|
||||||
|
buttons: [
|
||||||
|
Button{
|
||||||
|
text: 'Run end'
|
||||||
|
state: 'end'
|
||||||
|
},
|
||||||
|
Button{
|
||||||
|
text: 'Swimming to end'
|
||||||
|
state: 'end'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
'start': Question{
|
||||||
|
title: 'Start question'
|
||||||
|
description: 'This first question, start'
|
||||||
|
buttons: [
|
||||||
|
Button{
|
||||||
|
text: 'start'
|
||||||
|
state: 'q1'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
175
our_benchmark/benchmark.v
Normal file
175
our_benchmark/benchmark.v
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
module our_benchmark
|
||||||
|
|
||||||
|
import time
|
||||||
|
import math
|
||||||
|
|
||||||
|
@[noinit]
|
||||||
|
pub struct CustomBenchmark {
|
||||||
|
pub mut:
|
||||||
|
n i64 // Количество итераций
|
||||||
|
bench_func ?fn()! // функция которая тестируется, не может быть пустой
|
||||||
|
bench_time time.Duration // время выполнения бенчмарка дефолтно 1 секунда, проверка на то что не может быть меньше секунды?
|
||||||
|
is_parallel bool // флаг паралельного запуска, дефолтно 0
|
||||||
|
benchmark_result BenchmarkResult // сюда складываются результаты бенчмарка
|
||||||
|
timer_on bool
|
||||||
|
start_time time.Time
|
||||||
|
duration time.Duration
|
||||||
|
failed bool
|
||||||
|
start_memory usize
|
||||||
|
start_allocs usize
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BenchmarkResult {
|
||||||
|
pub mut:
|
||||||
|
n i64 // Количество итераций
|
||||||
|
t time.Duration // Общее затраченное время
|
||||||
|
mem usize // память
|
||||||
|
allocs usize // аллокации
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_custom_benchmark (bench_func fn()!,n i64,duration time.Duration,is_parallel bool) !CustomBenchmark{
|
||||||
|
if bench_func == voidptr(0) {
|
||||||
|
return error('Benchmark function cannot be empty')
|
||||||
|
}
|
||||||
|
|
||||||
|
mut check_duration := duration
|
||||||
|
if duration == 0 { check_duration = time.second }
|
||||||
|
|
||||||
|
return CustomBenchmark{
|
||||||
|
n:n
|
||||||
|
bench_func: bench_func
|
||||||
|
bench_time: check_duration
|
||||||
|
is_parallel: is_parallel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut b CustomBenchmark) run_benchmark(){
|
||||||
|
mut n := b.n // нужно для того чтобы если нам передали n о после прогрева его оставить
|
||||||
|
b.run_n(1)
|
||||||
|
// тут проверяем если n != 0 это проверка на то что не передали, по дефолту будет всегда 1 n
|
||||||
|
if n != 0{
|
||||||
|
b.n =n
|
||||||
|
b.run_n(n)
|
||||||
|
}else {
|
||||||
|
for !b.failed && b.duration < b.bench_time && n < 1000000000 {
|
||||||
|
// предсказываем количество итераций, исходя из предыдущих результатов
|
||||||
|
n = b.predict_n()
|
||||||
|
// выполняем бенчмарк n раз
|
||||||
|
b.run_n(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.benchmark_result.n = b.n
|
||||||
|
b.benchmark_result.t = b.duration
|
||||||
|
|
||||||
|
b.benchmark_result.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
// функция run_n выполняет бенчмарк указанное количество раз (n итераций)
|
||||||
|
// обеспечивает синхронизацию, управляет временем выполнения и обрабатывает ошибки
|
||||||
|
fn (mut b CustomBenchmark) run_n(n i64) {
|
||||||
|
// очищаем память для минимизации влияния сборщика мусора на результаты бенчмарка
|
||||||
|
gc_collect()
|
||||||
|
// устанавливаем количество итераций
|
||||||
|
b.n = n
|
||||||
|
// сбрасываем и запускаем таймер для измерения времени выполнения
|
||||||
|
b.reset_timer()
|
||||||
|
b.start_timer()
|
||||||
|
|
||||||
|
// извлекаем функцию бенчмарка
|
||||||
|
mut f := b.bench_func or {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// выполняем бенчмарк n раз в цикле
|
||||||
|
for i := i64(0); i < n; i++ {
|
||||||
|
f() or {
|
||||||
|
// если во время выполнения произошла ошибка, устанавливаем флаг ошибки и выводим сообщение
|
||||||
|
b.failed = true
|
||||||
|
eprintln('Error: $err')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// останавливаем таймер после выполнения всех итераций
|
||||||
|
b.stop_timer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// predict_n предсказывает количество итераций для следующего запуска бенчмарка,
|
||||||
|
// основываясь на предыдущих результатах выполнения
|
||||||
|
fn (mut b CustomBenchmark) predict_n() i64 {
|
||||||
|
mut goal_ns := b.bench_time.nanoseconds() // Не меняем, поэтому берем из ресивера
|
||||||
|
prev_iters := b.n // Берем последний n который был из b.n так как в run_n мы его записываем
|
||||||
|
mut prev_ns := b.duration.nanoseconds()
|
||||||
|
|
||||||
|
if prev_ns <= 0 {
|
||||||
|
prev_ns = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
mut n := goal_ns *prev_iters
|
||||||
|
n = n / prev_ns
|
||||||
|
n += n / 5
|
||||||
|
|
||||||
|
n = math.min(n, 100 * b.n)
|
||||||
|
n = math.max(n, b.n + 1)
|
||||||
|
n = math.min(n, 1000000000)
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut b CustomBenchmark) reset_timer() {
|
||||||
|
if b.timer_on {
|
||||||
|
b.start_time = time.now()
|
||||||
|
b.start_memory = gc_memory_use()
|
||||||
|
b.start_allocs = gc_heap_usage().bytes_since_gc
|
||||||
|
}
|
||||||
|
b.duration = 0
|
||||||
|
b.benchmark_result.mem = 0
|
||||||
|
b.benchmark_result.allocs = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut b CustomBenchmark) start_timer() {
|
||||||
|
if !b.timer_on{
|
||||||
|
b.start_time = time.now()
|
||||||
|
b.start_memory = gc_memory_use()
|
||||||
|
b.start_allocs = gc_heap_usage().bytes_since_gc
|
||||||
|
b.timer_on = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut b CustomBenchmark) stop_timer() {
|
||||||
|
if b.timer_on{
|
||||||
|
b.duration += time.since(b.start_time)
|
||||||
|
b.benchmark_result.mem +=gc_memory_use() - b.start_memory
|
||||||
|
b.benchmark_result.allocs += gc_heap_usage().bytes_since_gc - b.start_allocs
|
||||||
|
b.timer_on = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (r BenchmarkResult) ns_per_op() i64 {
|
||||||
|
if r.n <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return r.t.nanoseconds() / i64(r.n)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (r BenchmarkResult) allocs_per_op() i64 {
|
||||||
|
if r.n <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return i64(r.allocs) / i64(r.n)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (r BenchmarkResult) alloced_bytes_per_op() i64 {
|
||||||
|
if r.n <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return i64(r.mem) / i64(r.n)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (r BenchmarkResult) show() {
|
||||||
|
println('Iterations: ${r.n}')
|
||||||
|
println('Total Duration: ${r.t}')
|
||||||
|
println('ns/op: ${r.ns_per_op()}')
|
||||||
|
println('B/op: ${r.alloced_bytes_per_op()}')
|
||||||
|
println('allocs/op: ${r.allocs_per_op()}')
|
||||||
|
}
|
179
our_benchmark/benchmark_test.v
Normal file
179
our_benchmark/benchmark_test.v
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
module our_benchmark
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
// if n == 0, n predict == 1
|
||||||
|
fn test_predict_n_zero() {
|
||||||
|
mut b := CustomBenchmark{
|
||||||
|
n: 0,
|
||||||
|
duration: 0,
|
||||||
|
bench_time: time.second,
|
||||||
|
}
|
||||||
|
expected := 1
|
||||||
|
println(b.predict_n())
|
||||||
|
assert b.predict_n() == expected
|
||||||
|
}
|
||||||
|
|
||||||
|
// n can't be more 1000000000
|
||||||
|
fn test_predict_n_limit() {
|
||||||
|
mut b := CustomBenchmark{
|
||||||
|
n: 10000000000,
|
||||||
|
duration: 0,
|
||||||
|
bench_time: time.second,
|
||||||
|
}
|
||||||
|
expected := 1000000000
|
||||||
|
assert b.predict_n() == expected
|
||||||
|
}
|
||||||
|
|
||||||
|
// если произошла ошибка в бенч функции то флаг failed должен быть помечен в тру, n = 1
|
||||||
|
fn test_fn_with_error() {
|
||||||
|
f := fn() ! {
|
||||||
|
return error('error')
|
||||||
|
}
|
||||||
|
mut bench := our_benchmark.new_custom_benchmark(f, 0, 0, false)or {
|
||||||
|
eprintln('Error creating benchmark: $err')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bench.run_benchmark()
|
||||||
|
|
||||||
|
assert bench.failed == true
|
||||||
|
assert bench.benchmark_result.n == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_n_must_be_over_1(){
|
||||||
|
f := fn() ! {
|
||||||
|
mut i := 0
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
mut bench := our_benchmark.new_custom_benchmark(f, 0, 0, false)or {
|
||||||
|
eprintln('Error creating benchmark: $err')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bench.run_benchmark()
|
||||||
|
|
||||||
|
assert bench.benchmark_result.n > 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_n(){
|
||||||
|
f := fn() ! {
|
||||||
|
mut i := 0
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
mut bench := our_benchmark.new_custom_benchmark(f, 1000, 0, false)or {
|
||||||
|
eprintln('Error creating benchmark: $err')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bench.run_benchmark()
|
||||||
|
|
||||||
|
assert bench.benchmark_result.n == 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
// n == 2 так как прогрев = 1 итерация + 1 итерация == 2
|
||||||
|
fn test_max_bench_time(){
|
||||||
|
f := fn() ! {
|
||||||
|
time.sleep(500* time.millisecond)
|
||||||
|
}
|
||||||
|
mut bench := our_benchmark.new_custom_benchmark(f, 0, 0, false)or {
|
||||||
|
eprintln('Error creating benchmark: $err')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bench.run_benchmark()
|
||||||
|
|
||||||
|
assert bench.benchmark_result.n == 2
|
||||||
|
assert bench.benchmark_result.t >= time.second
|
||||||
|
}
|
||||||
|
|
||||||
|
// проверка на то что n обновляется корректно после run_n
|
||||||
|
fn test_n_updated_correct() {
|
||||||
|
mut b := CustomBenchmark{
|
||||||
|
n: 1,
|
||||||
|
bench_time: time.second,
|
||||||
|
bench_func: fn () ! {
|
||||||
|
mut i := 0
|
||||||
|
i++
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
b.run_n(100)
|
||||||
|
assert b.n == 100
|
||||||
|
|
||||||
|
b.run_n(1)
|
||||||
|
assert b.n == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// проверка на то как вообще работает
|
||||||
|
fn test_performance() {
|
||||||
|
scheduler := [func_1,func_2,func_3]
|
||||||
|
expected := [false,false,false]
|
||||||
|
mut actual := []bool{}
|
||||||
|
|
||||||
|
for i in scheduler{
|
||||||
|
mut bench := our_benchmark.new_custom_benchmark(i, 0, 0, false)or {
|
||||||
|
eprintln('Error creating benchmark: $err')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bench.run_benchmark()
|
||||||
|
actual << bench.failed
|
||||||
|
}
|
||||||
|
|
||||||
|
assert expected.len == actual.len
|
||||||
|
for i:=0;i<expected.len;i++{
|
||||||
|
assert expected[i] == actual[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn func_1() !{
|
||||||
|
mut arr := []int{}
|
||||||
|
appender(mut arr)
|
||||||
|
assert arr.len == 10
|
||||||
|
}
|
||||||
|
|
||||||
|
fn appender(mut arr []int){
|
||||||
|
if arr.len==10{
|
||||||
|
return
|
||||||
|
}
|
||||||
|
arr << 1
|
||||||
|
appender(mut arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn func_2() !{
|
||||||
|
target := 2
|
||||||
|
arr := [1,2,3,4,5,6,7,8,9,10]
|
||||||
|
|
||||||
|
mut left := 0
|
||||||
|
mut right := arr.len-1
|
||||||
|
|
||||||
|
for left<=right{
|
||||||
|
mid :=left+(right-left)/2
|
||||||
|
if arr[mid] == target{
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if arr[mid]<target{
|
||||||
|
left = mid + 1
|
||||||
|
}
|
||||||
|
if arr[mid]>target{
|
||||||
|
right = mid - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn func_3() !{
|
||||||
|
mut arr := [10,2,13,4,5,16,7,1,9,20]
|
||||||
|
|
||||||
|
for i :=0; i<arr.len-1;i++{
|
||||||
|
for j:=0;j<arr.len-i-1;j++{
|
||||||
|
if arr[j] > arr[j+1]{
|
||||||
|
arr[j],arr[j+1]=arr[j+1],arr[j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
33
respondent/respondent.go
Normal file
33
respondent/respondent.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package respondent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/telegram/models"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/telegram/state_manager"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Respondent struct {
|
||||||
|
Manager *stateManager.StateManager
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRespondent(m *stateManager.StateManager) *Respondent {
|
||||||
|
return &Respondent{
|
||||||
|
Manager: m,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Respondent) Respond(startState string) {
|
||||||
|
question := r.Manager.Questions[r.Manager.State]
|
||||||
|
if len(question.Buttons) > 0 {
|
||||||
|
var choice models.Button
|
||||||
|
for {
|
||||||
|
choice = question.Buttons[rand.Intn(len(question.Buttons))]
|
||||||
|
fmt.Println("choice it:", choice.Text)
|
||||||
|
if choice.State != startState {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.Manager.Listener(choice.State)
|
||||||
|
}
|
||||||
|
}
|
27
respondent/respondent.v
Normal file
27
respondent/respondent.v
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
module respondent
|
||||||
|
|
||||||
|
import rand
|
||||||
|
import state_manager
|
||||||
|
|
||||||
|
pub struct Respondent {
|
||||||
|
pub mut:
|
||||||
|
manager &state_manager.StateManager
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut r Respondent) respond(start_state string) {
|
||||||
|
mut question := r.manager.questions[r.manager.state]
|
||||||
|
if question.buttons.len > 0 {
|
||||||
|
mut choice := question.buttons[0]
|
||||||
|
for {
|
||||||
|
choice = question.buttons[rand.intn(question.buttons.len) or {
|
||||||
|
eprintln('Failed rand.intn: ${err}')
|
||||||
|
return
|
||||||
|
}]
|
||||||
|
//println('choice it: ${choice}')
|
||||||
|
if choice.state != start_state {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.manager.listener(choice.state)
|
||||||
|
}
|
||||||
|
}
|
41
state_manager/stateManager.go
Normal file
41
state_manager/stateManager.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package stateManager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/telegram/client"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/telegram/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StateManager struct {
|
||||||
|
Questions map[string]models.Question
|
||||||
|
State string
|
||||||
|
client *client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type Deps struct {
|
||||||
|
Questions map[string]models.Question
|
||||||
|
State string
|
||||||
|
Client *client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStateManager(deps Deps) *StateManager {
|
||||||
|
return &StateManager{
|
||||||
|
Questions: deps.Questions,
|
||||||
|
State: deps.State,
|
||||||
|
client: deps.Client,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *StateManager) Listener(state string) {
|
||||||
|
sm.State = state
|
||||||
|
sm.SendQuestion()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *StateManager) SendQuestion() {
|
||||||
|
question := sm.Questions[sm.State]
|
||||||
|
message := fmt.Sprintf("%s\n%s", question.Title, question.Description)
|
||||||
|
for _, button := range question.Buttons {
|
||||||
|
message += fmt.Sprintf("\n%s", button.Text)
|
||||||
|
}
|
||||||
|
sm.client.SendMessage(message)
|
||||||
|
}
|
26
state_manager/stateManager.v
Normal file
26
state_manager/stateManager.v
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
module state_manager
|
||||||
|
|
||||||
|
import strconv
|
||||||
|
import models
|
||||||
|
import client
|
||||||
|
|
||||||
|
pub struct StateManager {
|
||||||
|
pub mut:
|
||||||
|
questions map[string]models.Question
|
||||||
|
state string
|
||||||
|
client &client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut sm StateManager) listener(state string) {
|
||||||
|
sm.state = state
|
||||||
|
sm.send_question()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut sm StateManager) send_question() {
|
||||||
|
mut question := sm.questions[sm.state]
|
||||||
|
mut message := unsafe { strconv.v_sprintf('%s\n%s', question.title, question.description)}
|
||||||
|
for _, button in question.buttons {
|
||||||
|
message += unsafe { strconv.v_sprintf('\n%s', button.text)}
|
||||||
|
}
|
||||||
|
sm.client.send_message(message)
|
||||||
|
}
|
55
tg_handle/tg.v
Normal file
55
tg_handle/tg.v
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
module tg_handle
|
||||||
|
|
||||||
|
import dariotarantini.vgram
|
||||||
|
|
||||||
|
pub struct TgBot {
|
||||||
|
pub:
|
||||||
|
bot vgram.Bot
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_tg_bot(token string){
|
||||||
|
bot := vgram.new_bot(token)
|
||||||
|
b := TgBot{
|
||||||
|
bot: bot
|
||||||
|
}
|
||||||
|
spawn b.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (b TgBot) start() ! {
|
||||||
|
mut new := true
|
||||||
|
mut last_offset := 0
|
||||||
|
for {
|
||||||
|
mut updates := b.bot.get_updates(offset: last_offset, limit: 100)
|
||||||
|
for update in updates {
|
||||||
|
if last_offset < update.update_id {
|
||||||
|
last_offset = update.update_id
|
||||||
|
if new{
|
||||||
|
new = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if update.message.text == "/start" {
|
||||||
|
b.start_handler(update)!
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
b.message_handler(update)!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (b TgBot) start_handler(update vgram.Update) ! {
|
||||||
|
b.bot.send_message(
|
||||||
|
chat_id: update.message.from.id.str(),
|
||||||
|
text: 'Привет!'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (b TgBot) message_handler(update vgram.Update) ! {
|
||||||
|
if !update.message.text.starts_with('/') {
|
||||||
|
b.bot.send_message(
|
||||||
|
chat_id: update.message.from.id.str(),
|
||||||
|
text: 'Кнопка: $update.message.text'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
7184
treedata.json
Normal file
7184
treedata.json
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user