Skip to content

add lock on TinyDB #170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 69 commits into from
Nov 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
ba975a5
tf 2.7
previ Jan 21, 2022
e437748
revert tf 2.1
previ Jan 22, 2022
9d5fdf4
bump numpy ver
previ Jan 23, 2022
7c7ee87
bump requirements_stub
previ Jan 24, 2022
ba9729e
bump requirements_stub
previ Jan 24, 2022
80c3b6f
led ws2812b
previ Jan 25, 2022
e14de56
led ws2812b
previ Jan 25, 2022
bcbba45
led ws2812b
previ Jan 25, 2022
f2c224a
led ws2812b
previ Jan 26, 2022
140285d
add listMusicPackages api
previ Jan 29, 2022
d88b342
fix musicPackage export
previ Jan 30, 2022
cfab93b
remove coderbot-copy.py
previ Jan 30, 2022
c90ccf8
fix music package removal
previ Feb 1, 2022
db7bfde
Merge branch 'develop' of https://github.com/CoderBotOrg/backend into…
previ Feb 1, 2022
1c69018
v1 feature parity
previ Feb 1, 2022
0cefff7
fix #155
previ Feb 6, 2022
a6eec09
fix program status and log with v2
previ Feb 7, 2022
d1d3882
update ci
previ Feb 8, 2022
55023d5
add default activity init
previ Mar 6, 2022
5763bc8
add default activity init
previ Mar 7, 2022
a3f291b
add default activity
previ Mar 9, 2022
ca1b990
activity default parameters
previ Mar 12, 2022
c096602
bullseye wip
previ May 28, 2022
fa63bb4
bullseye wip
previ May 29, 2022
5d50a5e
Update audioControls.py
previ May 29, 2022
0f3e5f6
bullseye wip
previ May 29, 2022
1266d83
Update audio.py
previ Jun 8, 2022
e032049
update stock activities
previ Jun 8, 2022
d58a6d8
Update program.py
previ Jun 11, 2022
94e2c76
Update activity_default.json
previ Jun 12, 2022
a1ec6ac
Update coderbot.py
previ Jun 18, 2022
ea027ed
no longer init_activities
previ Jun 28, 2022
c71cfc7
move init_activities on frontend for i18n
previ Jun 28, 2022
795fd4c
fix v4.1 bugs
previ Jul 3, 2022
06ad987
fix 4.1 bugs
previ Jul 3, 2022
a5699ba
fix 4.1 bugs
previ Jul 3, 2022
e6b0ffb
fix 4.1 bugs
previ Jul 3, 2022
0cadf12
fix 4.1 bugs
previ Jul 3, 2022
6dc5198
fix v4.1 bugs
previ Jul 3, 2022
94985a5
fix 4.1 bugs
previ Jul 4, 2022
76b850a
fix 4.1 bugs
previ Jul 4, 2022
216b1f8
fix 4.1 bugs
previ Jul 4, 2022
3dc0eb3
fix 4.1 bugs
previ Jul 5, 2022
02d3601
fix 4.1 bugs
previ Jul 6, 2022
5de8c00
Update wifi.py
previ Jul 7, 2022
86bcc8d
Update wifi.py
previ Jul 8, 2022
9ab32b3
add CONTRIBUTING.md (#162)
avivace Jul 8, 2022
66441fa
merge master
previ Jul 8, 2022
5454eaa
fix event
previ Aug 13, 2022
cc4792a
Refactor API (#166)
previ Oct 23, 2022
f378bd4
Refactor api v3 (#167)
previ Oct 25, 2022
0920d25
wip #164
previ Oct 26, 2022
e78c71f
wip #164
previ Oct 26, 2022
6a32faa
wip #164
previ Oct 26, 2022
a82fe38
wip #164
previ Oct 27, 2022
5f84450
wip #164
previ Oct 27, 2022
53537b3
wip #164
previ Oct 27, 2022
4b106cb
merge master into develop
previ Oct 27, 2022
5d37d71
status
previ Oct 30, 2022
154d61e
status
previ Oct 30, 2022
83af554
status
previ Oct 30, 2022
ba22222
status
previ Oct 30, 2022
45c7241
status
previ Oct 30, 2022
d685974
add stub
previ Oct 31, 2022
d7dfa33
stub
previ Oct 31, 2022
78fc103
remove unnecessary updatePckages dir
previ Nov 1, 2022
7eba733
merge master into develop
previ Nov 1, 2022
0aee02d
disable cicleci
previ Nov 1, 2022
aa9c069
add thread lock on TinyDB
previ Nov 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
41 changes: 39 additions & 2 deletions .github/workflows/build_backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
container: coderbot/coderbot-ci:3.9-bullseye-slim
steps:
- uses: actions/checkout@v3 # Checking out the repo
- run: pip install -r requirements_stub.txt
- run: pip install -r docker/stub/requirements.txt
- run: |
export PYTHONPATH=./coderbot:./stub:./test
mkdir test-reports
Expand Down Expand Up @@ -58,7 +58,7 @@ jobs:
type=ref,event=pr
# push event
type=sha,enable=true,prefix=git-,format=short
- uses: actions/checkout@v2 # Checking out the repo
- uses: actions/checkout@v3 # Checking out the repo
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
Expand All @@ -74,9 +74,46 @@ jobs:
uses: docker/build-push-action@v3
with:
push: true
build-args: CODERBOT_VERSION=${{github.ref_name}}-${{github.sha}}
platforms: linux/arm/v7
tags: ${{ steps.meta.outputs.tags }}
context: .
file: docker/Dockerfile
cache-from: type=registry,ref=ghcr.io/coderbotorg/backend:latest
cache-to: type=inline

release-stub:
needs: [test]
runs-on: ubuntu-latest
steps:
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
# list of Docker images to use as base name for tags
images: ghcr.io/coderbotorg/backend
# generate Docker tags based on the following events/attributes
tags: |
# always latest
type=raw,value=stub-latest
- uses: actions/checkout@v3 # Checking out the repo
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v3
with:
push: true
build-args: CODERBOT_VERSION=${{github.ref_name}}-${{github.sha}}
platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }}
context: .
file: docker/stub/Dockerfile
cache-from: type=registry,ref=ghcr.io/coderbotorg/backend:stub-latest
cache-to: type=inline
51 changes: 28 additions & 23 deletions coderbot/activity.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from tinydb import TinyDB, Query

from threading import Lock
# Programs and Activities databases
class Activities():
_instance = None
Expand All @@ -13,34 +13,39 @@ def get_instance(cls):
def __init__(self):
self.activities = TinyDB("data/activities.json")
self.query = Query()
self.lock = Lock()

def load(self, name, default):
if name and default is None:
activities = self.activities.search(self.query.name == name)
if len(activities) > 0:
return activities[0]
elif default is not None:
if len(self.activities.search(self.query.default == True)) > 0:
return self.activities.search(self.query.default == True)[0]
with self.lock:
if name and default is None:
activities = self.activities.search(self.query.name == name)
if len(activities) > 0:
return activities[0]
elif default is not None:
if len(self.activities.search(self.query.default == True)) > 0:
return self.activities.search(self.query.default == True)[0]
return None
return None
return None

def save(self, name, activity):
# if saved activity is "default", reset existing default activity to "non-default"
if activity.get("default", False) is True:
self.activities.update({'default': False})
if self.activities.search(self.query.name == name) == []:
self.activities.insert(activity)
else:
self.activities.update(activity, self.query.name == activity["name"])
with self.lock:
# if saved activity is "default", reset existing default activity to "non-default"
if activity.get("default", False) is True:
self.activities.update({'default': False})
if self.activities.search(self.query.name == name) == []:
self.activities.insert(activity)
else:
self.activities.update(activity, self.query.name == activity["name"])

def delete(self, name):
activities = self.activities.search(self.query.name == name)
if len(activities) > 0:
activity = activities[0]
if activity.get("default", False) is True:
self.activities.update({'default': True}, self.query.stock == True)
self.activities.remove(self.query.name == activity["name"])
with self.lock:
activities = self.activities.search(self.query.name == name)
if len(activities) > 0:
activity = activities[0]
if activity.get("default", False) is True:
self.activities.update({'default': True}, self.query.stock == True)
self.activities.remove(self.query.name == activity["name"])

def list(self):
return self.activities.all()
with self.lock:
return self.activities.all()
71 changes: 8 additions & 63 deletions coderbot/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ def get_status():
uptime = 0
try:
uptime = subprocess.check_output(["uptime"]).decode('utf-8').replace('\n', '')
except:
except Exception:
pass

internet_status = False
try:
urllib.request.urlopen("https://coderbot.org")
internet_status = True
except:
except Exception:
pass

return {'internet_status': internet_status,
Expand All @@ -87,42 +87,20 @@ def get_info():
Expose informations about the CoderBot system.
(Cached method)
"""
backend_commit = "undefined"
coderbot_version = "undefined"
update_status = "ok"
device = {}
motors = 'undefined'

try:
# manifest.json is generated while building/copying the backend
with open('manifest.json', 'r') as f:
metadata = json.load(f)
backend_commit = metadata["backend_commit"][0:7]
coderbot_version = metadata["backend_version"][0:7]
except Exception:
pass

try:
encoder = bool(Config.read().get('encoder'))
if(encoder):
motors = 'DC encoder motors'
else:
motors = 'DC motors'
except Exception:
pass

serial = get_serial()

try:
device = Baleba.get_instance().device()
device = Balena.get_instance().device()
logging.info("device: %s", str(device))
except Exception:
pass
return { 'backend_commit': device.get("commit"),
'coderbot_version': coderbot_version,

return { 'release_commit': device.get("commit"),
'coderbot_version': os.getenv("CODERBOT_VERSION"),
'update_status': device.get("status"),
'kernel': device.get("os_version"),
'serial': serial,
'motors': motors }
'serial': serial }

prog = None
prog_engine = ProgramEngine.get_instance()
Expand Down Expand Up @@ -249,39 +227,6 @@ def deletePhoto(name):
except FileNotFoundError:
return 404

## System

def status():
sts = get_status()
# getting reset log file
data = []
try:
with open('/home/pi/coderbot/logs/reset_trigger_service.log', 'r') as log_file:
data = [x for x in log_file.read().split('\n') if x]
except Exception: # direct control case
pass # if file doesn't exist, no restore as ever been performed. return empty data


return {
"status": "ok",
"internetConnectivity": sts["internet_status"],
"temp": sts["temp"],
"uptime": sts["uptime"],
"log": data
}

def info():
inf = get_info()
return {
"model": 1,
"version": inf["coderbot_version"],
"backend commit build": inf["backend_commit"],
"kernel" : inf["kernel"],
"update status": inf["update_status"],
"serial": inf["serial"],
"motors": inf["motors"]
}

def restoreSettings():
Config.restore()
return restart()
Expand Down
10 changes: 5 additions & 5 deletions coderbot/balena/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,24 @@ def __init__(self):
def purge(self):
logging.debug("reset bot")
req = Request(f'{self.supervisor_address}/v1/purge?apikey={self.supervisor_key}', data=self.app_id_data, headers=self.headers, method='POST')
return urlopen(req).read()
return json.load(urlopen(req))

def shutdown(self):
logging.debug("shutdown bot")
req = Request(f'{self.supervisor_address}/v1/shutdown?apikey={self.supervisor_key}', headers=self.headers, method='POST')
return urlopen(req).read()
return json.load(urlopen(req))

def restart(self):
logging.debug("restarting bot")
req = Request(f'{self.supervisor_address}/v1/restart?apikey={self.supervisor_key}', data=self.app_id_data, headers=self.headers, method='POST')
return urlopen(req).read()
return json.load(urlopen(req))

def reboot(self):
logging.debug("reboot bot")
req = Request(f'{self.supervisor_address}/v1/reboot?apikey={self.supervisor_key}', headers=self.headers, method='POST')
return urlopen(req).read()
return json.load(urlopen(req))

def device(self):
logging.debug("reboot bot", f'{self.supervisor_address}get?apikey={self.supervisor_key}')
req = Request(f'{self.supervisor_address}/device?apikey={self.supervisor_key}', headers=self.headers, method='GET')
req = Request(f'{self.supervisor_address}/v1/device?apikey={self.supervisor_key}', headers=self.headers, method='GET')
return json.load(urlopen(req))
41 changes: 23 additions & 18 deletions coderbot/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import math
from tinydb import TinyDB, Query
from threading import Lock

import coderbot
import camera
Expand Down Expand Up @@ -80,6 +81,7 @@ def __init__(self):
self._programs = TinyDB(PROGRAMS_DB)
# initialise DB from default programs
query = Query()
self.lock = Lock()
for dirname, dirnames, filenames, in os.walk(PROGRAMS_PATH_DEFAULTS):
dirnames
for filename in filenames:
Expand All @@ -102,28 +104,31 @@ def prog_list(self):
return self._programs.all()

def save(self, program):
query = Query()
self._program = program
program_db_entry = self._program.as_dict()
if self._programs.search(query.name == program.name) != []:
self._programs.update(program_db_entry, query.name == program.name)
else:
self._programs.insert(program_db_entry)
with self.lock:
query = Query()
self._program = program
program_db_entry = self._program.as_dict()
if self._programs.search(query.name == program.name) != []:
self._programs.update(program_db_entry, query.name == program.name)
else:
self._programs.insert(program_db_entry)

def load(self, name):
query = Query()
program_db_entries = self._programs.search(query.name == name)
if len(program_db_entries) > 0:
prog_db_entry = program_db_entries[0]
logging.debug(prog_db_entry)
self._program = Program.from_dict(prog_db_entry)
return self._program
return None
with self.lock:
query = Query()
program_db_entries = self._programs.search(query.name == name)
if len(program_db_entries) > 0:
prog_db_entry = program_db_entries[0]
logging.debug(prog_db_entry)
self._program = Program.from_dict(prog_db_entry)
return self._program
return None

def delete(self, name):
query = Query()
program_db_entries = self._programs.search(query.name == name)
self._programs.remove(query.name == name)
with self.lock:
query = Query()
program_db_entries = self._programs.search(query.name == name)
self._programs.remove(query.name == name)

def create(self, name, code):
self._program = Program(name, code)
Expand Down
4 changes: 2 additions & 2 deletions coderbot/v1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ paths:
description: "upload failed"
/system/status:
get:
operationId: "api.status"
operationId: "api.get_status"
summary: "Bot general informations, execution status and reset log file"
tags:
- System operations
Expand All @@ -422,7 +422,7 @@ paths:
description: Test ended.
/system/info:
get:
operationId: "api.info"
operationId: "api.get_info"
summary: "Bot general informations and execution status"
tags:
- System operations
Expand Down
7 changes: 5 additions & 2 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ RUN pip install --no-cache-dir -r /tmp/requirements.txt
RUN mkdir -p /coderbot && \
mkdir -p /coderbot/data && \
mkdir -p /coderbot/logs && \
mkdir -p /coderbot/updatePackages && \
mkdir -p /coderbot/cnn_modules && \
mkdir -p /coderbot/coderbot && \
mkdir -p /coderbot/defaults && \
Expand All @@ -63,5 +62,9 @@ ADD sounds /coderbot/sounds/.
ADD docker/scripts/*.sh /tmp/.
RUN /tmp/install_generic_cnn_models.sh
RUN /tmp/install_lib_firmware.sh
ADD docker/start.sh /coderbot/.

ENTRYPOINT cd /coderbot && modprobe i2c-dev && python3 coderbot/main.py
ARG CODERBOT_VERSION
ENV CODERBOT_VERSION=${CODERBOT_VERSION}

ENTRYPOINT /coderbot/start.sh
3 changes: 3 additions & 0 deletions docker/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

cd /coderbot && modprobe i2c-dev && python3 coderbot/main.py
Loading