Introduction
OJ Lab is an open source organization which aims to 🤔 find out and 🙌 share the solutions to build modernized online judge system.
This book will help you keep in pace with the development of OJ Lab.
Judge API v1
[WIP]
POST /api/v1/judge
{
src: "",
package_slug: ""
}
GET /api/v1/status
return spare
| busy
Problem API V1
[WIP]
GET /api/v1/problem
[WIP]
POST /api/v1/problem
Should wait package to be put.
PUT /api/v1/problem/:problem-slug/package
Replace/put the problem package in S3 storage, mark the problem as package uploaded.
POST /api/v1/problem/:problem-slug/judge
Check problem is package uploaded, then send judge task to Judger.
Recommanded Setup
Pure '*nix' environment may be better, but some member of OJ Lab use 'Windows + WSL'.
Windows
Recommended to build development environment in WSL with VSCode remote.
Make sure to have a reliable network to avoid download problems.
Golang
Install by brew with brew install go
.
You may need to reopen VSCode to refresh go environment.
Also, you may need to change go proxy for essential installs go env -w GOPROXY=https://goproxy.cn
.
Add GOPATH to PATH
Add export PATH="$PATH:$(go env GOPATH)/bin"
to your cli profile,
or you might miss some ability installed by go.
Docker
Install docker desktop in windows host.
Model Design Rules
🎯 You should design your model first before providing any kind of service.
Briefly speeking, OJ Lab Service runs with models which mainly shows in JSON and mapped by GORM in database.
Usage of Struct Tag
To reduce the complexity of model usage, we should design as fewer models as possible, and the relationship between models should be well designed.
Fields Control
In different situations,
the model will carry different fields.
(
For example,
the password
field should be hidden in most cases,
but it should be shown when creating a new user.
Also,
to avoid security problems,
the password
field will not saved directly to database,
but a hashed_password
field will be saved instead.
)
Model Associations
The model may have associations with other models.
(
For example,
the user
model may have a role
field,
which is a list of role
model.
Also,
the role
model may have a user
field,
which is a list of user
model.
)
Usually, controlling these associations is very complex,
but we can rely on GORM to make it easier.
Solutions
Thanks to the ability of struct tag in JSON and GORM, we nearly don't need to write any model conversion codes.
The user struct is defined as below:
type User struct {
MetaFields
Account string `gorm:"primaryKey" json:"account"`
Name string `json:"name"`
Password *string `gorm:"-:all" json:"password,omitempty"`
HashedPassword string `gorm:"not null" json:"-"`
Roles []*Role `gorm:"many2many:user_roles;" json:"roles,omitempty"`
Email string `gorm:"unique" json:"email,omitempty"`
Mobile string `gorm:"unique" json:"mobile,omitempty"`
}
type Role struct {
Name string `gorm:"primaryKey" json:"name"`
Users []*User `gorm:"many2many:user_roles" json:"users,omitempty"`
}
You can try refering the following links to learn:
We don't get a very good JSON usage document for now. Simply search for 'go JSON struct tag' on the internet may help.
Model Naming
The struct and field naming will effect the table naming for GORM. Although GORM provides a way to customize table name, but it can be really confuse when struct convert to structs and got different table names.
So it will be better to keep the default naming rules and make table and struct names the same. Then we will get fewer struct being defined, and less conversion which may cause confusion.
Another thing which may cause confusion is when you are trying to define model like Tag
, Form
etc.
These names only describe the model itself,
but do not show any relationship between models,
also there are some other models with the same name (like there might be many Tag
models).
So it will be better to add some prefix to the model name,
but don't use the parent model name as prefix (like UserTag
or ProblemTag
).
Try to be more specific for the real usage (like AlgorithmTag
).
Run Judge V1
⚠️ This function is still under develop now, not promising the usage will be changed in the future.
Usage with Judger
You should run both oj-lab-services
and judger
in the same network.
By default judger
will listen on :8000
,
if you change it,
you should also change judger.host
in oj-lab-services
's config
(an override config is more recommended, see override.example.toml
).
Run judger
cargo run --bin judge-server
Run oj-lab-services
make run
Test APIs
Both judger
and oj-lab-services
provide a postman
API collection in project root.
Import them into Postman and test.
Recommanded Setup
Should be able to run in any environment, but we recommand to use WSL
with VSCode Remote
.
*unix environment will be more convenient in installation.
*unix
Install NVM
Visit NVM Installing and Updating for further steps.
Install Node.js by NVM
If it's the first time you use NVM,
simply run: nvm install 18
.
18
is the currently the latest big LTS version of Node.js, check Node.js Releases for more information.
If you have already installed Node.js by NVM,
run nvm use 18
to enable Node.js 18.
You should also run nvm alias default 18
if you want to set Node.js 18 as default.
Mock by MSW
🥰 OJ Lab front support developing without backend by MSW.
Usage
To enable MSW mock server, run npx msw init public/ --save
.
Check more information in MSW Getting Started.
Decision to Start Service Development
In the past few months, we all aims to build the most essentail part of an online judge system: The judge machine.
But recently I found it's really difficult to decide which functionality the service will be needed for the judger.
So we decide to restart the development of oj-lab-service, to find out what functionalities we will need in the future.
Milestones
- Development environment prepare (Including installation guide)
- Golang
- Postgres (Dev container + Ways to setup and clean datas)
- S3 Proxy (Store problem packages)
- Problem manage service implementation
- APIs to import problem packages (Store in S3 and DB)