From e2fc8696c88fb59c356f6165d55314c1dc32df4e Mon Sep 17 00:00:00 2001 From: sergystepanov Date: Wed, 8 Apr 2020 23:01:02 +0300 Subject: [PATCH] Add multi-os Github release workflow (#159) --- .github/workflows/release.yml | 207 ++++++++++++++++++++++++++++++++++ .gitignore | 1 + Makefile | 70 +++++++++++- README.md | 49 ++++---- 4 files changed, 300 insertions(+), 27 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..d66a4341 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,207 @@ +# ------------------------------------------------------------------------ +# Release workflow for multiple OSes (Linux x64, macOS x64, Windows x64) +# ------------------------------------------------------------------------ +# +---------------+ +---------------+ +# | BUILD | +---------------+ | PUBLISH | +# +---------------+ | RELEASE | +---------------+ +# | compile | +---------------+ | upload build | +# | | | | | | | | +# | nix ---> | -> | get release | -> | <-- nix | +# | mac ------> | | (use old) | | <--- mac | +# | win ----> | | | <- | <---- win | +# +---------------+ +---------------+ +---------------+ +# ------------------------------------------------------------------------ +# Usage: +# This workflow adds multi-os application builds when v-prefixed tags +# pushed into the repository, e.g. git tag v9001 & git push --tags or +# a new Github release is created with such tags. +# ------------------------------------------------------------------------ + +name: Release +# run only when pushing v-prefixed SemVer tags (e.g. v1.0.0, v2.0.1, and etc.) +on: + push: + tags: + - 'v*' +env: + go-version: 1.13 + app-name: cloud-game + app-arch: x86_64 +jobs: + # run app build for each OS in parallel + build: + name: Build + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + env: + release-dir: _release + steps: + - name: Get the source + uses: actions/checkout@v2 + - name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: ${{ env.go-version }} + - name: Set up Go environment + shell: bash + # add Go's bin folder into environmet (to be able to call its tools) + run: | + echo "::set-env name=GOPATH::$(go env GOPATH)" + echo "::add-path::$(go env GOPATH)/bin" + + - name: Get Linux dev libraries and tools + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y make pkg-config libvpx-dev libopus-dev libopusfile-dev + + - name: Get MacOS dev libraries and tools + if: matrix.os == 'macos-latest' + run: | + brew install libvpx pkg-config opus opusfile + + - name: Get Windows dev libraries and tools + if: matrix.os == 'windows-latest' + uses: numworks/setup-msys2@v1 + with: + msystem: MINGW64 + path-type: inherit + + - name: Load Go modules maybe? + uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Build Windows app + if: matrix.os == 'windows-latest' + run: | + msys2do pacman -S --noconfirm --needed make mingw-w64-x86_64-gcc mingw-w64-x86_64-pkg-config mingw-w64-x86_64-dlfcn mingw-w64-x86_64-libvpx mingw-w64-x86_64-opusfile + msys2do make release RELEASE_DIR=${{ env.release-dir }} DLIB_SEARCH_PATTERN=/mingw.*dll CORE_EXT=dll + + - name: Build Linux app + if: matrix.os == 'ubuntu-latest' + run: | + make release RELEASE_DIR=${{ env.release-dir }} DLIB_SEARCH_PATTERN=/usr/lib.*\\\\s CORE_EXT=so + + - name: Build macOS app + if: matrix.os == 'macos-latest' + run: | + # skip copy libs due to outrageous otool behaviour, depend on sys install + # should be recursive + paths rewritten to @executable_path + # lddx seems to be working ok + go get github.com/jtanx/lddx + make release RELEASE_DIR=${{ env.release-dir }} DLIB_ALTER=true DLIB_TOOL="lddx -r -c" CORE_EXT=dylib + + - name: Save built app for upload + uses: actions/upload-artifact@v1 + with: + name: ${{ runner.os }} + path: ${{ env.release-dir }} + + release: + name: Create or find Github release + needs: build + runs-on: ubuntu-latest + steps: + - name: Trying to find existing release + uses: actions/github-script@0.9.0 + id: release_search + with: + github-token: ${{secrets.GITHUB_TOKEN}} + result-encoding: string + script: | + try { + const release = await github.repos.getReleaseByTag({ + owner: context.repo.owner, + repo: context.repo.repo, + tag: context.ref.replace('refs/tags/', '') + }); + return release.data.upload_url; + } catch (ignored) {} + return ''; + - name: Create new release maybe? + id: create_release + if: steps.release_search.outputs.result == '' + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + draft: false + prerelease: false + # pass assets upload url of existing or new release + # between jobs (VMs) through txt files + - name: Get release upload URL + run: | + echo '${{ steps.create_release.outputs.upload_url }}${{ steps.release_search.outputs.result }}' > upload_url + - name: Save release upload URL + uses: actions/upload-artifact@v1 + with: + name: upload_url + path: ./ + + publish: + name: Publish + needs: release + strategy: + matrix: + # should be same as runner.os + target-os: [Linux, macOS, Windows] + include: + - target-os: Linux + compress: tar -zcf + archive-ext: tar.gz + archive-mime: tar + - target-os: macOS + compress: tar -zcf + archive-ext: tar.gz + archive-mime: tar + - target-os: Windows + compress: zip -qq -r + archive-ext: zip + archive-mime: zip + runs-on: ubuntu-latest + steps: + - name: Get version tag + id: get_version + run: | + echo ::set-output name=version::${GITHUB_REF#refs/tags/} + - name: Get release upload url + uses: actions/download-artifact@v1 + with: + name: upload_url + - name: Read release upload url + id: upload_url + run: | + value=`cat upload_url/upload_url` + echo "::set-output name=url::$value" + - name: Get the build + uses: actions/download-artifact@v1 + with: + name: ${{ matrix.target-os }} + - name: Compress the build + id: compress + # compress all the files without a parent dir + # (cd into arch dir -> make archive in its parent -> go back) + run: | + cd ./${{ matrix.target-os }} + archive='${{ env.app-name }}-${{ steps.get_version.outputs.version }}-${{ matrix.target-os }}-${{ env.app-arch }}' + compress='${{ matrix.compress }} ../${archive,,}.${{ matrix.archive-ext }} *' + eval $compress + cd ../ + echo ::set-output name=archive_name::${archive,,}.${{ matrix.archive-ext }} + - name: Upload release asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.upload_url.outputs.url }} + asset_path: ./${{ steps.compress.outputs.archive_name }} + asset_name: ${{ steps.compress.outputs.archive_name }} + asset_content_type: application/${{ matrix.archive-mime }} diff --git a/.gitignore b/.gitignore index a4b303e8..309caa48 100644 --- a/.gitignore +++ b/.gitignore @@ -60,5 +60,6 @@ bin/ .coverage.out _output/ ./build +release/ .dockerignore diff --git a/Makefile b/Makefile index f6521701..35c8bfca 100644 --- a/Makefile +++ b/Makefile @@ -58,14 +58,16 @@ cover: clean: @rm -rf bin @rm -rf build - @go clean + @go clean ./cmd/* + +build: + go build -a -tags netgo -ldflags '-w' -o bin/coordinator ./cmd/coordinator + go build -a -tags netgo -ldflags '-w' -o bin/worker ./cmd/worker dev.tools: ./hack/scripts/install_tools.sh -dev.build: compile - go build -a -tags netgo -ldflags '-w' -o bin/coordinator ./cmd/coordinator - go build -a -tags netgo -ldflags '-w' -o bin/worker ./cmd/worker +dev.build: compile build dev.build-local: go build -o bin/coordinator ./cmd/coordinator @@ -81,3 +83,63 @@ dev.run-docker: docker rm cloud-game-local || true # Coordinator and worker should be run separately. docker run --privileged -v $PWD/games:/cloud-game/games -d --name cloud-game-local -p 8000:8000 -p 9000:9000 cloud-game-local bash -c "coordinator --v=5 & worker --coordinatorhost localhost:8000" + +# RELEASE +# Builds the app for new release. +# +# Folder structure: +# release +# - coordinator/ +# - web/ +# - coordinator +# - worker/ +# - assets/ +# - emulator/libretro/cores/ (filtered by extension) +# - games/ +# - worker +# +# params: +# - RELEASE_DIR: the name of the output folder (default: _release). +# - DLIB_TOOL: the name of a dynamic lib copy tool (with params) (e.g., ldd -x -y; defalut: ldd). +# - DLIB_SEARCH_PATTERN: a grep filter of the output of the DLIB_TOOL (e.g., mylib.so; default: .*so). +# Be aware that this search pattern will return only matched regular expression part and not the whole line. +# de. -> abc def ghj -> def +# Makefile special symbols should be escaped with \. +# - DLIB_ALTER: a special flag to use altered dynamic copy lib tool for macOS only. +# - CORE_EXT: a file extension of the cores to copy into the release. +# +# example: +# make release DLIB_TOOL="ldd -x" DLIB_SEARCH_PATTERN=/usr/lib.*\\\\s LIB_EXT=so +# +RELEASE_DIR ?= release +DLIB_TOOL ?= ldd +DLIB_SEARCH_PATTERN ?= .*so +DLIB_ALTER ?= false +CORE_EXT ?= * +COORDINATOR_DIR = ./$(RELEASE_DIR)/coordinator +WORKER_DIR = ./$(RELEASE_DIR)/worker +CORES_DIR = assets/emulator/libretro/cores +GAMES_DIR = assets/games +.PHONY: release +.SILENT: release +release: clean build + rm -rf ./$(RELEASE_DIR) && mkdir ./$(RELEASE_DIR) + mkdir $(COORDINATOR_DIR) && mkdir $(WORKER_DIR) + cp ./bin/coordinator $(COORDINATOR_DIR) && cp ./bin/worker $(WORKER_DIR) + chmod +x $(COORDINATOR_DIR)/coordinator $(WORKER_DIR)/worker + ifeq ($(DLIB_ALTER),false) + for bin in $$($(DLIB_TOOL) $(WORKER_DIR)/worker | grep -o $(DLIB_SEARCH_PATTERN)); \ + do cp -v "$$bin" $(WORKER_DIR); \ + done + else + $(DLIB_TOOL) $(WORKER_DIR) $(WORKER_DIR)/worker + endif + cp -R ./web $(COORDINATOR_DIR) + mkdir -p $(WORKER_DIR)/$(GAMES_DIR) + ifneq (,$(wildcard ./$(GAMES_DIR))) + cp -R ./$(GAMES_DIR) $(WORKER_DIR)/assets + endif + mkdir -p $(WORKER_DIR)/$(CORES_DIR) + ifneq (,$(wildcard ./$(CORES_DIR)/*.$(CORE_EXT))) + cp -R ./$(CORES_DIR)/*.$(CORE_EXT) $(WORKER_DIR)/$(CORES_DIR) + endif diff --git a/README.md b/README.md index ef41d4a3..d71cff64 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,22 @@ # CloudRetro -**Open-source Cloud Gaming Service For Retro Games** -**Video demo**: https://www.youtube.com/watch?v=GUBrJGAxZZg + +Release status + +**Open-source Cloud Gaming Service For Retro Games** +**Video demo**: https://www.youtube.com/watch?v=GUBrJGAxZZg **My Slide at GopherconVN2019**: https://docs.google.com/presentation/d/1VFv8l2hVUINv2U36r7L11g4Oa_zVjHlr6MYymUbQXT4/edit?usp=sharing ## Introduction -CloudRetro provides an open-source cloud gaming platform for retro games. It started as an experiment for testing cloud gaming performance with [WebRTC](https://github.com/pion/webrtc/) and [libretro](https://www.libretro.com/), and now it aims to deliver the most modern and convenient gaming experience through the technology. +CloudRetro provides an open-source cloud gaming platform for retro games. It started as an experiment for testing cloud gaming performance with [WebRTC](https://github.com/pion/webrtc/) and [libretro](https://www.libretro.com/), and now it aims to deliver the most modern and convenient gaming experience through the technology. -Theoretically, in cloud gaming, games are run on remote servers and media are streamed to the player optimally to ensure the most comfortable user interaction. It opens the ability to play any retro games on web-browser directly, which are fully compatible with multi-platform like Desktop, Android, ~~IOS~~. It enhances crowdplay ([TwitchPlaysPokemon](https://en.wikipedia.org/wiki/Twitch_Plays_Pok%C3%A9mon)) with realtime interaction. E.g: [Play Pokemon Emerald together](http://cloudretro.io/?id=652e45d78d2b91cd%7CPokemon%20-%20Emerald%20Version%20%28U%29). +Theoretically, in cloud gaming, games are run on remote servers and media are streamed to the player optimally to ensure the most comfortable user interaction. It opens the ability to play any retro games on web-browser directly, which are fully compatible with multi-platform like Desktop, Android, ~~IOS~~. It enhances crowdplay ([TwitchPlaysPokemon](https://en.wikipedia.org/wiki/Twitch_Plays_Pok%C3%A9mon)) with realtime interaction. E.g: [Play Pokemon Emerald together](http://cloudretro.io/?id=652e45d78d2b91cd%7CPokemon%20-%20Emerald%20Version%20%28U%29). ## Try the service at -Single play: **[http://cloudretro.io](http://cloudretro.io)** -Crowd play: **[Pokemon Emerald](http://cloudretro.io/?id=652e45d78d2b91cd%7CPokemon%20-%20Emerald%20Version%20%28U%29)** -*Chrome and Chrome on Android is recommended. It's not working on iPhone and some other explorers. Click help button in the game UI to see keyboard mapping.* +Single play: **[http://cloudretro.io](http://cloudretro.io)** +Crowd play: **[Pokemon Emerald](http://cloudretro.io/?id=652e45d78d2b91cd%7CPokemon%20-%20Emerald%20Version%20%28U%29)** +*Chrome and Chrome on Android is recommended. It's not working on iPhone and some other explorers. Click help button in the game UI to see keyboard mapping.* -\*In ideal network condition and less resource contention on servers, the game will run smoothly as in the video demo. Because I only hosted the platform on limited servers in US East, US West, Eu, Singapore, you may experience some latency issues + connection problem. You can try hosting the service following the instruction the next section to have a better sense of performance. +\*In ideal network condition and less resource contention on servers, the game will run smoothly as in the video demo. Because I only hosted the platform on limited servers in US East, US West, Eu, Singapore, you may experience some latency issues + connection problem. You can try hosting the service following the instruction the next section to have a better sense of performance. | Screenshot | Screenshot | | :--------------------------------------------: | :--------------------------------------------: | @@ -31,7 +34,7 @@ Crowd play: **[Pokemon Emerald](http://cloudretro.io/?id=652e45d78d2b91cd%7CPoke ## Run on local by Docker -You try running the server directly by `make dev.run-docker`. It will spawn a docker environment and you can access the service on `localhost:8000`. +You try running the server directly by `make dev.run-docker`. It will spawn a docker environment and you can access the service on `localhost:8000`. ## Development environment @@ -77,18 +80,18 @@ Because the coordinator and workers need to run simultaneously. Workers connect - [Wiki](https://github.com/giongto35/cloud-game/wiki) ## FAQ -- [FAQ](https://github.com/giongto35/cloud-game/wiki/FAQ) +- [FAQ](https://github.com/giongto35/cloud-game/wiki/FAQ) ## Crowd Play, play game together -By clicking these deep link, you can join the game directly and play it together with other people. -- [Play Pokemon Emerald](http://cloudretro.io/?id=652e45d78d2b91cd%7CPokemon%20-%20Emerald%20Version%20%28U%29) +By clicking these deep link, you can join the game directly and play it together with other people. +- [Play Pokemon Emerald](http://cloudretro.io/?id=652e45d78d2b91cd%7CPokemon%20-%20Emerald%20Version%20%28U%29) - [Fire Emblem](http://cloudretro.io/?id=314ea4d7f9c94d25___Fire%20Emblem%20%28U%29%20%5B%21%5D) - [Advance War](http://cloudretro.io/?id=10fe582a7635b039___Advance%20Wars%20%28USA%29) - [Harvest Moon](http://cloudretro.io/?id=3f7462269e976303___Harvest%20Moon%20-%20Back%20to%20Nature%20%28USA%29) -- [Play Pokemon Fire Red](http://cloudretro.io/?id=68bf168be6728020___Pokemon%20-%20Fire%20Red%20Version%20%28U%29%20%28V1.1%29) -- [Mario](http://cloudretro.io/?id=1953c570fee1f9e4___Super%20Mario%20Bros) +- [Play Pokemon Fire Red](http://cloudretro.io/?id=68bf168be6728020___Pokemon%20-%20Fire%20Red%20Version%20%28U%29%20%28V1.1%29) +- [Mario](http://cloudretro.io/?id=1953c570fee1f9e4___Super%20Mario%20Bros) -And you can host the new game by yourself by accessing [cloudretro.io](http://cloudretro.io) and click "share" button to generate a deeplink to your current game. +And you can host the new game by yourself by accessing [cloudretro.io](http://cloudretro.io) and click "share" button to generate a deeplink to your current game. _Disclaimer: You may experience lagging when joining a room because the room is in a different zone. In that case, you should create a new room for crowd play._ ![screenshot](docs/img/crowdplay.gif) @@ -100,17 +103,17 @@ _Disclaimer: You may experience lagging when joining a room because the room is ## Credits -* *Pion* Webrtc team for the incredible Golang Webrtc library and their supports https://github.com/pion/webrtc/. -* *libretro/kivutar* Golang libretro https://github.com/libretro/go-nanoarch and https://www.libretro.com/. +* *Pion* Webrtc team for the incredible Golang Webrtc library and their supports https://github.com/pion/webrtc/. +* *libretro/kivutar* Golang libretro https://github.com/libretro/go-nanoarch and https://www.libretro.com/. * *gen2brain* for the h264 go encoder https://github.com/gen2brain/x264-go -* *poi5305* for the video encoding https://github.com/poi5305/go-yuv2webRTC. -* *fogleman* for the NES emulator https://github.com/fogleman/nes. +* *poi5305* for the video encoding https://github.com/poi5305/go-yuv2webRTC. +* *fogleman* for the NES emulator https://github.com/fogleman/nes. ## Author -Nguyen Huu Thanh -https://www.linkedin.com/in/huuthanhnguyen/ +Nguyen Huu Thanh +https://www.linkedin.com/in/huuthanhnguyen/ -Tri Dang Minh -https://trich.im +Tri Dang Minh +https://trich.im