fix: messages in separate file

This commit is contained in:
GitBluub
2023-04-03 01:57:48 +09:00
parent 445b949fa8
commit f1f7500b44
2 changed files with 350 additions and 344 deletions
+77
View File
@@ -0,0 +1,77 @@
from dataclasses import dataclass
from typing import Literal, Tuple
from validated_dc import ValidatedDC, get_errors, is_valid
@dataclass
class InvalidMessage:
message: str
@dataclass
class StartMessage(ValidatedDC):
id: int
bearer: str
mode: Literal["normal", "practice"]
type: Literal["start"] = "start"
@dataclass
class EndMessage(ValidatedDC):
type: Literal["end"] = "end"
@dataclass
class NoteOnMessage(ValidatedDC):
time: int
note: int
id: int
type: Literal["note_on"] = "note_on"
@dataclass
class NoteOffMessage(ValidatedDC):
time: int
note: int
id: int
type: Literal["note_off"] = "note_off"
@dataclass
class PauseMessage(ValidatedDC):
paused: bool
time: int
type: Literal["pause"] = "pause"
message_map = {
"start": StartMessage,
"end": EndMessage,
"note_on": NoteOnMessage,
"note_off": NoteOffMessage,
"pause": PauseMessage,
}
def getMessage() -> (
Tuple[
StartMessage
| EndMessage
| NoteOnMessage
| NoteOffMessage
| PauseMessage
| InvalidMessage,
str,
]
):
try:
msg = input()
obj = json.loads(msg)
res = message_map[obj["type"]](**obj)
if is_valid(res):
return res, msg
else:
return InvalidMessage(str(get_errors(res))), msg
except Exception as e:
return InvalidMessage(str(e)), ""
+52 -123
View File
@@ -6,14 +6,20 @@ import operator
import os import os
import select import select
import sys import sys
from dataclasses import dataclass
from typing import Literal, Tuple
import requests import requests
from chroma_case.Key import Key from chroma_case.Key import Key
from chroma_case.Message import (
EndMessage,
InvalidMessage,
NoteOffMessage,
NoteOnMessage,
PauseMessage,
StartMessage,
getMessage,
)
from chroma_case.Partition import Partition from chroma_case.Partition import Partition
from mido import MidiFile from mido import MidiFile
from validated_dc import ValidatedDC, get_errors, is_valid
BACK_URL = os.environ.get("BACK_URL") or "http://back:3000" BACK_URL = os.environ.get("BACK_URL") or "http://back:3000"
MUSICS_FOLDER = os.environ.get("MUSICS_FOLDER") or "/musics/" MUSICS_FOLDER = os.environ.get("MUSICS_FOLDER") or "/musics/"
@@ -27,108 +33,26 @@ NORMAL = 0
PRACTICE = 1 PRACTICE = 1
@dataclass
class InvalidMessage:
message: str
@dataclass
class StartMessage(ValidatedDC):
id: int
bearer: str
mode: Literal["normal", "practice"]
type: Literal["start"] = "start"
@dataclass
class EndMessage(ValidatedDC):
type: Literal["end"] = "end"
@dataclass
class NoteOnMessage(ValidatedDC):
time: int
note: int
id: int
type: Literal["note_on"] = "note_on"
@dataclass
class NoteOffMessage(ValidatedDC):
time: int
note: int
id: int
type: Literal["note_off"] = "note_off"
@dataclass
class PauseMessage(ValidatedDC):
paused: bool
time: int
type: Literal["pause"] = "pause"
message_map = {
"start": StartMessage,
"end": EndMessage,
"note_on": NoteOnMessage,
"note_off": NoteOffMessage,
"pause": PauseMessage,
}
def getMessage() -> (
Tuple[
StartMessage
| EndMessage
| NoteOnMessage
| NoteOffMessage
| PauseMessage
| InvalidMessage,
str,
]
):
try:
msg = input()
obj = json.loads(msg)
res = message_map[obj["type"]](**obj)
if is_valid(res):
return res, msg
else:
return InvalidMessage(str(get_errors(res))), msg
except Exception as e:
return InvalidMessage(str(e)), ""
def send(o): def send(o):
print(json.dumps(o), flush=True) print(json.dumps(o), flush=True)
class Scorometer: class Scorometer:
def __init__(self, mode, midiFile, song_id, user_id) -> None: def __init__(self, mode: int, midiFile: str, song_id: int, user_id: int) -> None:
self.partition = self.getPartition(midiFile) self.partition: Partition = self.getPartition(midiFile)
self.practice_partition: list[list[Key]] = self.getPracticePartition(mode)
self.keys_down = [] self.keys_down = []
self.mode = mode self.mode: int = mode
self.song_id = song_id self.song_id: int = song_id
self.user_id = user_id self.user_id: int = user_id
self.score = 0 self.score: int = 0
self.missed = 0 self.missed: int = 0
self.perfect = 0 self.perfect: int = 0
self.great = 0 self.great: int = 0
self.good = 0 self.good: int = 0
self.difficulties = {} self.difficulties = {}
if mode == PRACTICE:
get_start = operator.attrgetter("start")
self.practice_partition = [
list(g)
for _, g in itertools.groupby(
sorted(self.partition.notes, key=get_start), get_start
)
]
else:
self.practice_partition: list[list[Key]] = []
def getPartition(self, midiFile): def getPartition(self, midiFile: str):
notes = [] notes = []
s = 3500 s = 3500
notes_on = {} notes_on = {}
@@ -150,13 +74,25 @@ class Scorometer:
notes_on[d["note"]] = s # 500 notes_on[d["note"]] = s # 500
return Partition(midiFile, notes) return Partition(midiFile, notes)
def getPracticePartition(self, mode: int) -> list[list[Key]]:
get_start = operator.attrgetter("start")
return (
[
list(g)
for _, g in itertools.groupby(
sorted(self.partition.notes, key=get_start), get_start
)
]
if mode == PRACTICE
else []
)
def handleNoteOn(self, message: NoteOnMessage): def handleNoteOn(self, message: NoteOnMessage):
_key = message.note key = message.note
timestamp = message.time is_down = any(x[0] == key for x in self.keys_down)
is_down = any(x[0] == _key for x in self.keys_down)
if not is_down: if not is_down:
self.keys_down.append((_key, timestamp)) self.keys_down.append((key, message.time))
logging.debug({"note": _key}) logging.debug({"note": key})
def handleNoteOff(self, message: NoteOffMessage): def handleNoteOff(self, message: NoteOffMessage):
_key = message.note _key = message.note
@@ -164,7 +100,6 @@ class Scorometer:
down_since = next(since for (h_key, since) in self.keys_down if h_key == _key) down_since = next(since for (h_key, since) in self.keys_down if h_key == _key)
self.keys_down.remove((_key, down_since)) self.keys_down.remove((_key, down_since))
key = Key(_key, down_since, (timestamp - down_since)) key = Key(_key, down_since, (timestamp - down_since))
# debug({key: key})
to_play = next( to_play = next(
( (
i i
@@ -176,6 +111,7 @@ class Scorometer:
if to_play is None: if to_play is None:
self.score -= 50 self.score -= 50
logging.info("Invalid key.") logging.info("Invalid key.")
self.sendScore(message.id, "wrong key", "wrong key")
else: else:
timingScore, timingInformation = self.getTiming(key, to_play) timingScore, timingInformation = self.getTiming(key, to_play)
self.score += ( self.score += (
@@ -189,34 +125,33 @@ class Scorometer:
self.sendScore(message.id, timingScore, timingInformation) self.sendScore(message.id, timingScore, timingInformation)
def handleNoteOnPractice(self, message: NoteOnMessage): def handleNoteOnPractice(self, message: NoteOnMessage):
_key = message.note key = message.note
timestamp = message.time is_down = any(x[0] == key for x in self.keys_down)
is_down = any(x[0] == _key for x in self.keys_down)
if not is_down: if not is_down:
self.keys_down.append((_key, timestamp)) self.keys_down.append((key, message.time))
logging.debug({"note": _key}) logging.debug({"note": key})
def handleNoteOffPractice(self, message: NoteOffMessage): def handleNoteOffPractice(self, message: NoteOffMessage):
_key = message.note _key = message.note
timestamp = message.time
# is_down = any(x[0] == _key for x in self.keys_down)
down_since = next(since for (h_key, since) in self.keys_down if h_key == _key) down_since = next(since for (h_key, since) in self.keys_down if h_key == _key)
self.keys_down.remove((_key, down_since)) self.keys_down.remove((_key, down_since))
key = Key(_key, down_since, (timestamp - down_since)) key = Key(_key, down_since, (message.time - down_since))
keys_to_play = next( keys_to_play = next(
(i for i in self.practice_partition if any(x.done is not True for x in i)), (i for i in self.practice_partition if any(x.done is not True for x in i)),
None, None,
) )
if keys_to_play is None: if keys_to_play is None:
logging.info("Key sent but there is no keys to play") logging.info("Invalid key.")
self.score -= 50 self.score -= 50
self.sendScore(message.id, "wrong key", "wrong key")
return return
to_play = next( to_play = next(
(i for i in keys_to_play if i.key == key.key and i.done is not True), None (i for i in keys_to_play if i.key == key.key and i.done is not True), None
) )
if to_play is None: if to_play is None:
logging.info(f"Wrong key sent: {message.note} with id {message.id}")
self.score -= 50 self.score -= 50
logging.info("Invalid key.") self.sendScore(message.id, "wrong key", "wrong key")
else: else:
timingScore, _ = self.getTiming(key, to_play) timingScore, _ = self.getTiming(key, to_play)
self.score += ( self.score += (
@@ -235,10 +170,13 @@ class Scorometer:
def getTimingScore(self, key: Key, to_play: Key): def getTimingScore(self, key: Key, to_play: Key):
tempo_percent = abs((key.duration / to_play.duration) - 1) tempo_percent = abs((key.duration / to_play.duration) - 1)
if tempo_percent < 0.3: if tempo_percent < 0.3:
self.perfect += 1
timingScore = "perfect" timingScore = "perfect"
elif tempo_percent < 0.5: elif tempo_percent < 0.5:
self.great += 1
timingScore = "great" timingScore = "great"
else: else:
self.good += 1
timingScore = "good" timingScore = "good"
return timingScore return timingScore
@@ -299,24 +237,15 @@ class Scorometer:
def gameLoop(self): def gameLoop(self):
while True: while True:
if select.select(
[
sys.stdin,
],
[],
[],
0.0,
)[0]:
message, line = getMessage() message, line = getMessage()
logging.info(f"handling message {line}") logging.info(f"handling message {line}")
self.handleMessage(message, line) self.handleMessage(message, line)
else:
pass
def endGame(self): def endGame(self):
for i in self.partition.notes: for i in self.partition.notes:
if i.done is False: if i.done is False:
self.score -= 50 self.score -= 50
self.missed += 1
send( send(
{ {
"overallScore": self.score, "overallScore": self.score,