Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
with:
go-version: "1.23"
- name: Run coverage
run: go test -race -coverprofile=coverage.txt -covermode=atomic
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
with:
Expand Down
53 changes: 53 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
name: docker
on:
push:
# Publish `main` as Docker `latest` image.
branches:
- main
# Publish `v1.2.3` tags as releases.
tags:
- v*.*.*
jobs:
package:
runs-on: ubuntu-latest
env:
dockerfile: Dockerfile
image_name: iomz/golemu
platforms: linux/amd64,linux/arm64
registry: ghcr.io
steps:
- uses: actions/checkout@v4
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
# list of Docker images to use as base name for tags
images: |
${{ env.registry }}/${{ env.image_name }}
# generate Docker tags based on the following events/attributes
tags: |
type=schedule
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.registry }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
platforms: "${{ env.platforms }}"
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@
*.swp
sim/*
vendor/*

coverage.out
golemu
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
The MIT License (MIT)
Copyright © 2016 Iori MIZUTANI <iori.mizutani@gmail.com>
Copyright © 2025 Iori MIZUTANI <iori.mizutani@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to deal
Expand Down
33 changes: 28 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,35 @@ Mizutani, I., & Mitsugi, J. (2016). A Multicode and Portable RFID Tag Events Emu

# Installation

Install [dep](https://github.com/golang/dep) in your system first.
## From Source

```bash
# Install the latest version
go install github.com/iomz/golemu/cmd/golemu@latest

# Or install from a local clone
git clone https://github.com/iomz/golemu.git
cd golemu
go install ./cmd/golemu

# Verify installation
golemu --help
```
$ go get github.com/iomz/golemu
$ cd $GOPATH/src/github.com/iomz/golemu
$ dep ensure && go install .

**Note:** Make sure `$GOPATH/bin` or `$HOME/go/bin` is in your `PATH` environment variable to use the `golemu` command directly.

## Build Locally

```bash
# Clone the repository
git clone https://github.com/iomz/golemu.git
cd golemu

# Build the binary
go build -o golemu ./cmd/golemu

# Run directly
./golemu --help
```

# Synopsis
Expand Down Expand Up @@ -98,4 +121,4 @@ See the LICENSE file.

## Author

Iori Mizutani (iomz)
Iori Mizutani (@iomz)
133 changes: 133 additions & 0 deletions api/handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package api

import (
"net/http"

"github.com/fatih/structs"
"github.com/gin-gonic/gin"
"github.com/iomz/go-llrp"
"github.com/iomz/golemu/tag"
log "github.com/sirupsen/logrus"
)

// Handler handles API requests
type Handler struct {
tagManagerChan chan tag.Manager
}

// NewHandler creates a new API handler
func NewHandler(tagManagerChan chan tag.Manager) *Handler {
return &Handler{
tagManagerChan: tagManagerChan,
}
}

// PostTag handles tag addition requests
func (h *Handler) PostTag(c *gin.Context) {
var json []llrp.TagRecord
if err := c.ShouldBindJSON(&json); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request", "details": err.Error()})
return
}

if res := h.reqAddTag(json); res == "error" {
c.JSON(http.StatusConflict, gin.H{"error": "One or more tags already exist"})
} else {
c.JSON(http.StatusCreated, gin.H{"message": "Tags added successfully"})
}
}

// DeleteTag handles tag deletion requests
func (h *Handler) DeleteTag(c *gin.Context) {
var json []llrp.TagRecord
if err := c.ShouldBindJSON(&json); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request", "details": err.Error()})
return
}

if res := h.reqDeleteTag(json); res == "error" {
c.JSON(http.StatusNotFound, gin.H{"error": "One or more tags not found"})
} else {
c.JSON(http.StatusOK, gin.H{"message": "Tags deleted successfully"})
}
}

// GetTags handles tag retrieval requests
func (h *Handler) GetTags(c *gin.Context) {
tagList := h.reqRetrieveTag()
c.JSON(http.StatusOK, tagList)
}

func (h *Handler) reqAddTag(req []llrp.TagRecord) string {
validTags := []*llrp.Tag{}
for _, t := range req {
tagObj, err := llrp.NewTag(&llrp.TagRecord{
PCBits: t.PCBits,
EPC: t.EPC,
})
if err != nil {
log.Errorf("error creating tag: %v", err)
return "error"
}

validTags = append(validTags, tagObj)
}

for _, tagObj := range validTags {
add := tag.Manager{
Action: tag.AddTags,
Tags: []*llrp.Tag{tagObj},
}
h.tagManagerChan <- add
}

log.Debugf("add %v", req)
return "add"
}

func (h *Handler) reqDeleteTag(req []llrp.TagRecord) string {
hasError := false
for _, t := range req {
tagObj, err := llrp.NewTag(&llrp.TagRecord{
PCBits: t.PCBits,
EPC: t.EPC,
})
if err != nil {
log.Errorf("error creating tag: %v", err)
hasError = true
continue
}

deleteCmd := tag.Manager{
Action: tag.DeleteTags,
Tags: []*llrp.Tag{tagObj},
}
h.tagManagerChan <- deleteCmd
}

if hasError {
return "error"
}
log.Debugf("delete %v", req)
return "delete"
}

func (h *Handler) reqRetrieveTag() []map[string]interface{} {
retrieve := tag.Manager{
Action: tag.RetrieveTags,
Tags: []*llrp.Tag{},
}
h.tagManagerChan <- retrieve
retrieve = <-h.tagManagerChan
var tagList []map[string]interface{}
for _, tagObj := range retrieve.Tags {
t := structs.Map(llrp.NewTagRecord(*tagObj))
tagList = append(tagList, t)
}
log.Debugf("retrieve: %v", tagList)
return tagList
}
Loading