-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #86 from GNURub/master
JWT for HTTP-Operation API
- Loading branch information
Showing
37 changed files
with
684 additions
and
145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
# Created by .ignore support plugin (hsz.mobi) | ||
.idea | ||
dist | ||
room_keys.json | ||
.vscode | ||
.tmp | ||
vendor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Changelog | ||
All notable changes to this project will be documented in this file. | ||
|
||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
|
||
## [Unreleased] | ||
|
||
### Added | ||
- JSON Web Token support. | ||
``` json | ||
// .livego.json | ||
{ | ||
"jwt": { | ||
"secret": "testing", | ||
"algorithm": "HS256s" | ||
}, | ||
"server": [ | ||
{ | ||
"appname": "live", | ||
"liveon": "on", | ||
"hlson": "on" | ||
} | ||
] | ||
} | ||
``` | ||
- Use redis for store room keys | ||
``` json | ||
// .livego.json | ||
{ | ||
"redis_addr": "localhost:6379", | ||
"server": [ | ||
{ | ||
"appname": "live", | ||
"liveon": "on", | ||
"hlson": "on" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
### Changed | ||
- Show `players`. | ||
- Show `stream_id`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,17 +3,20 @@ WORKDIR /app | |
COPY go.mod go.sum ./ | ||
RUN go mod download | ||
COPY . . | ||
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o livego ./ | ||
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o livego . | ||
|
||
FROM alpine:latest | ||
LABEL maintainer="gwuhaolin <[email protected]>" | ||
LABEL maintainer="Ruben Cid Lara <[email protected]>" | ||
RUN mkdir -p /app/config | ||
WORKDIR /app | ||
ENV RTMP_PORT 1935 | ||
ENV HTTP_FLV_PORT 7001 | ||
ENV HLS_PORT 7002 | ||
ENV HTTP_OPERATION_PORT 8090 | ||
COPY --from=builder /app/config ./config | ||
COPY --from=builder /app/livego . | ||
EXPOSE ${RTMP_PORT} | ||
EXPOSE ${HTTP_FLV_PORT} | ||
EXPOSE ${HLS_PORT} | ||
EXPOSE ${HTTP_OPERATION_PORT} | ||
CMD ./livego | ||
ENTRYPOINT ["./livego"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,42 @@ | ||
# livego | ||
简单高效的直播服务器: | ||
- 安装和使用非常简单; | ||
- 纯 Golang 编写,性能高,跨平台; | ||
- 支持常用的传输协议、文件格式、编码格式; | ||
Simple and efficient live broadcast server: | ||
- Very simple to install and use; | ||
- Pure Golang, high performance, cross-platform; | ||
- Support commonly used transmission protocols, file formats, encoding formats; | ||
|
||
#### 支持的传输协议 | ||
#### Supported transport protocols | ||
- RTMP | ||
- AMF | ||
- HLS | ||
- HTTP-FLV | ||
|
||
#### 支持的容器格式 | ||
#### Supported container formats | ||
- FLV | ||
- TS | ||
|
||
#### 支持的编码格式 | ||
#### Supported encoding formats | ||
- H264 | ||
- AAC | ||
- MP3 | ||
- sMP3 | ||
|
||
## 安装 | ||
直接下载编译好的[二进制文件](https://github.com/gwuhaolin/livego/releases)后,在命令行中执行。 | ||
## Installation | ||
After directly downloading the compiled [binary file](https://github.com/gwuhaolin/livego/releases), execute it on the command line. | ||
|
||
#### 从 Docker 启动 | ||
执行`docker run -p 1935:1935 -p 7001:7001 -p 7002:7002 -d --name livego gwuhaolin/livego`启动 | ||
#### Boot from Docker | ||
Run `docker run -p 1935:1935 -p 7001:7001 -p 7002:7002 -d --name livego gnurub/livego` to start | ||
|
||
#### 从源码编译 | ||
1. 下载源码 `git clone https://github.com/gwuhaolin/livego.git` | ||
2. 去 livego 目录中 执行 `go build` | ||
#### Compile from source | ||
1. Download the source code `git clone https://github.com/gwuhaolin/livego.git` | ||
2. Go to the livego directory and execute `go build` | ||
|
||
## 使用 | ||
2. 启动服务:执行 `livego` 二进制文件启动 livego 服务; | ||
3. 上行推流:通过 `RTMP` 协议把视频流推送到 `rtmp://localhost:1935/live/movie`,例如使用 `ffmpeg -re -i demo.flv -c copy -f flv rtmp://localhost:1935/live/movie` 推送; | ||
4. 下行播放:支持以下三种播放协议,播放地址如下: | ||
- `RTMP`:`rtmp://localhost:1935/live/movie` | ||
- `FLV`:`http://127.0.0.1:7001/live/movie.flv` | ||
- `HLS`:`http://127.0.0.1:7002/live/movie.m3u8` | ||
## Use | ||
2. Start the service: execute the livego binary file to start the livego service; | ||
3. Upstream push: Push the video stream to `rtmp://localhost:1935/live/movie` through the` RTMP` protocol, for example, use `ffmpeg -re -i demo.flv -c copy -f flv rtmp://localhost:1935/live/movie` push; | ||
4. Downstream playback: The following three playback protocols are supported, and the playback address is as follows: | ||
-`RTMP`:`rtmp://localhost:1935/live/movie` | ||
-`FLV`:`http://127.0.0.1:7001/live/movie.flv` | ||
-`HLS`:`http://127.0.0.1:7002/live/movie.m3u8` | ||
|
||
### [Use with flv.js](https://github.com/gwuhaolin/blog/issues/3) | ||
|
||
### [和 flv.js 搭配使用](https://github.com/gwuhaolin/blog/issues/3) | ||
|
||
对Golang感兴趣?请看[Golang 中文学习资料汇总](http://go.wuhaolin.cn/) | ||
Interested in Golang? Please see [Golang Chinese Learning Materials Summary](http://go.wuhaolin.cn/) |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
package configure | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"math/rand" | ||
"sync" | ||
"time" | ||
|
||
"github.com/go-redis/redis/v7" | ||
) | ||
|
||
var RoomKeys = LoadRoomKey(*GetKeyFile()) | ||
|
||
var roomUpdated = false | ||
|
||
var saveInFile = true | ||
var redisCli *redis.Client | ||
|
||
func Init() { | ||
saveInFile = GetRedisAddr() == nil | ||
|
||
rand.Seed(time.Now().UnixNano()) | ||
if saveInFile { | ||
go func() { | ||
for { | ||
time.Sleep(15 * time.Second) | ||
if roomUpdated { | ||
RoomKeys.Save(*roomKeySaveFile) | ||
roomUpdated = false | ||
} | ||
} | ||
}() | ||
|
||
return | ||
} | ||
|
||
redisCli = redis.NewClient(&redis.Options{ | ||
Addr: *GetRedisAddr(), | ||
Password: *GetRedisPwd(), | ||
DB: 0, | ||
}) | ||
|
||
_, err := redisCli.Ping().Result() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
log.Printf("Redis connected") | ||
} | ||
|
||
type RoomKeysType struct { | ||
mapChanKey sync.Map | ||
mapKeyChan sync.Map | ||
} | ||
|
||
func LoadRoomKey(f string) *RoomKeysType { | ||
result := &RoomKeysType{ | ||
mapChanKey: sync.Map{}, | ||
mapKeyChan: sync.Map{}, | ||
} | ||
raw := map[string]string{} | ||
content, err := ioutil.ReadFile(f) | ||
if err != nil { | ||
log.Printf("Failed to read file %s for room keys", f) | ||
return result | ||
} | ||
if json.Unmarshal(content, &raw) != nil { | ||
log.Printf("Failed to unmarshal file %s for room keys", f) | ||
return result | ||
} | ||
for room, key := range raw { | ||
result.mapChanKey.Store(room, key) | ||
result.mapKeyChan.Store(key, room) | ||
} | ||
return result | ||
} | ||
|
||
func (r *RoomKeysType) Save(f string) { | ||
raw := map[string]string{} | ||
r.mapChanKey.Range(func(channel, key interface{}) bool { | ||
raw[channel.(string)] = key.(string) | ||
return true | ||
}) | ||
content, err := json.Marshal(raw) | ||
if err != nil { | ||
log.Println("Failed to marshal room keys") | ||
return | ||
} | ||
if ioutil.WriteFile(f, content, 0644) != nil { | ||
log.Println("Failed to save room keys") | ||
return | ||
} | ||
} | ||
|
||
// set/reset a random key for channel | ||
func (r *RoomKeysType) SetKey(channel string) (key string, err error) { | ||
if !saveInFile { | ||
for { | ||
key = randStringRunes(48) | ||
if _, err = redisCli.Get(key).Result(); err == redis.Nil { | ||
err = redisCli.Set(channel, key, 0).Err() | ||
if err != nil { | ||
return | ||
} | ||
|
||
err = redisCli.Set(key, channel, 0).Err() | ||
return | ||
} else if err != nil { | ||
return | ||
} | ||
} | ||
} | ||
|
||
for { | ||
key = randStringRunes(48) | ||
if _, found := r.mapKeyChan.Load(key); !found { | ||
r.mapChanKey.Store(channel, key) | ||
r.mapKeyChan.Store(key, channel) | ||
break | ||
} | ||
} | ||
roomUpdated = true | ||
return | ||
} | ||
|
||
func (r *RoomKeysType) GetKey(channel string) (newKey string, err error) { | ||
if !saveInFile { | ||
if newKey, err = redisCli.Get(channel).Result(); err == redis.Nil { | ||
newKey, err = r.SetKey(channel) | ||
log.Printf("[KEY] new channel [%s]: %s", channel, newKey) | ||
return | ||
} | ||
|
||
return | ||
} | ||
|
||
var key interface{} | ||
var found bool | ||
if key, found = r.mapChanKey.Load(channel); found { | ||
return key.(string), nil | ||
} | ||
newKey, err = r.SetKey(channel) | ||
log.Printf("[KEY] new channel [%s]: %s", channel, newKey) | ||
return | ||
} | ||
|
||
func (r *RoomKeysType) GetChannel(key string) (channel string, err error) { | ||
if !saveInFile { | ||
return redisCli.Get(key).Result() | ||
} | ||
|
||
chann, found := r.mapKeyChan.Load(key) | ||
if found { | ||
return chann.(string), nil | ||
} else { | ||
return "", fmt.Errorf("%s does not exists", key) | ||
} | ||
} | ||
|
||
func (r *RoomKeysType) DeleteChannel(channel string) bool { | ||
if !saveInFile { | ||
return redisCli.Del(channel).Err() != nil | ||
} | ||
|
||
key, ok := r.mapChanKey.Load(channel) | ||
if ok { | ||
r.mapChanKey.Delete(channel) | ||
r.mapKeyChan.Delete(key) | ||
return true | ||
} | ||
return false | ||
} | ||
|
||
func (r *RoomKeysType) DeleteKey(key string) bool { | ||
if !saveInFile { | ||
return redisCli.Del(key).Err() != nil | ||
} | ||
|
||
channel, ok := r.mapKeyChan.Load(key) | ||
if ok { | ||
r.mapChanKey.Delete(channel) | ||
r.mapKeyChan.Delete(key) | ||
return true | ||
} | ||
return false | ||
} | ||
|
||
// helpers | ||
var letterRunes = []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") | ||
|
||
func randStringRunes(n int) string { | ||
b := make([]rune, n) | ||
for i := range b { | ||
b[i] = letterRunes[rand.Intn(len(letterRunes))] | ||
} | ||
return string(b) | ||
} |
Oops, something went wrong.