trmnl_preview 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +46 -17
- data/bin/trmnlp +14 -0
- data/lib/trmnlp/api_client.rb +62 -0
- data/lib/{trmnl_preview → trmnlp}/app.rb +24 -12
- data/lib/trmnlp/cli.rb +51 -0
- data/lib/trmnlp/commands/base.rb +23 -0
- data/lib/trmnlp/commands/build.rb +22 -0
- data/lib/trmnlp/commands/login.rb +25 -0
- data/lib/trmnlp/commands/pull.rb +45 -0
- data/lib/trmnlp/commands/push.rb +43 -0
- data/lib/trmnlp/commands/serve.rb +25 -0
- data/lib/trmnlp/commands.rb +1 -0
- data/lib/trmnlp/config/app.rb +39 -0
- data/lib/trmnlp/config/plugin.rb +74 -0
- data/lib/trmnlp/config/project.rb +47 -0
- data/lib/trmnlp/config.rb +15 -0
- data/lib/trmnlp/context.rb +211 -0
- data/lib/{trmnl_preview → trmnlp}/custom_filters.rb +2 -1
- data/lib/trmnlp/paths.rb +50 -0
- data/lib/{trmnl_preview → trmnlp}/screen_generator.rb +1 -1
- data/lib/trmnlp/version.rb +5 -0
- data/lib/trmnlp.rb +13 -0
- data/trmnl_preview.gemspec +19 -12
- data/web/public/index.js +5 -1
- data/web/views/index.erb +2 -0
- data/web/views/render_html.erb +1 -1
- metadata +87 -24
- data/.ruby-version +0 -1
- data/config.example.toml +0 -14
- data/docs/preview.png +0 -0
- data/exe/trmnlp +0 -14
- data/lib/trmnl_preview/cmd/build.rb +0 -25
- data/lib/trmnl_preview/cmd/serve.rb +0 -31
- data/lib/trmnl_preview/cmd/usage.rb +0 -11
- data/lib/trmnl_preview/cmd/version.rb +0 -1
- data/lib/trmnl_preview/context.rb +0 -135
- data/lib/trmnl_preview/version.rb +0 -5
- data/lib/trmnl_preview.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51839346d4b2bd24698655d8e6a86a1a93aac73d2882a5b907072db9851ffa03
|
4
|
+
data.tar.gz: 0e54398757e865c8907f3b65b4046519dba2dced17d6d62ce3342b89ce2a5d75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e17bf9dba3a94a153c0182493d7b2ee597ba70b54177793fedae27a154817de8a79eb108a50194b5b5e0f1d2c012ff0b9047b9457cbdf52ad9b5e4d6331c6ab
|
7
|
+
data.tar.gz: a66a9b16b7c3512d018bd10a2444a7cfa4ecf335e9fd580583f27ac4cf6030c810bd48ab20878e3ec704b8f0faf64b7bc6e28ad08e585d1bf51ea3a01d0575fb
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,37 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.4.0
|
4
|
+
|
5
|
+
### Plugin Migration Strategy
|
6
|
+
|
7
|
+
The plugin directory structure has changed to better align with the [plugin archive format](https://help.usetrmnl.com/en/articles/10542599-importing-and-exporting-private-plugins#h_581fb988f0).
|
8
|
+
|
9
|
+
Here is a migration strategy for existing plugin repositories:
|
10
|
+
|
11
|
+
1. Create `.trmnlp.yml` and bring over preview settings from `config.toml` - [see README](README.md)
|
12
|
+
2. Rename directory `views/` to `src/`
|
13
|
+
3. Create `src/settings.yml` and bring over plugin settings from `config.toml` - [see TRMNL docs](https://help.usetrmnl.com/en/articles/10542599-importing-and-exporting-private-plugins#h_581fb988f0)
|
14
|
+
4. Delete `config.toml`
|
15
|
+
|
16
|
+
### Changes
|
17
|
+
|
18
|
+
- Change plugin directory structure (see README for details)
|
19
|
+
- Add `login`, `push`, and `pull` commands
|
20
|
+
- Bring up-to-date with latest private plugin features:
|
21
|
+
- Add `static` strategy
|
22
|
+
- Add polling features: multiple URLs, new verbs, and request body
|
23
|
+
- Add settings `dark_mode`, `no_screen_padding`, `custom_fields`
|
24
|
+
- Add interpolation of custom fields in `polling\_\*` options
|
25
|
+
- Add `{{ trmnl }}` variables
|
26
|
+
- Add `watch` config
|
27
|
+
- Add interpolation of environment variables in `.trmnlp.yml` via `{{ env }}`
|
28
|
+
- Add auto-reload when `.trmnlp.yml` or `settings.yml` changes
|
29
|
+
- Add variable display
|
30
|
+
- Fix crash when #poll_data fails (#12)
|
31
|
+
- Fix git runtime error in Docker container (#12)
|
32
|
+
|
33
|
+
|
34
|
+
|
3
35
|
## 0.3.2
|
4
36
|
|
5
37
|
- Add bitmap rendering
|
data/README.md
CHANGED
@@ -10,20 +10,25 @@ The server watches the filesystem for changes to the Liquid templates, seamlessl
|
|
10
10
|
|
11
11
|
## Creating a Plugin
|
12
12
|
|
13
|
-
This is the structure of a plugin
|
13
|
+
This is the structure of a plugin project.
|
14
14
|
|
15
15
|
```
|
16
|
-
|
16
|
+
.trmnlp.yml
|
17
|
+
src/
|
17
18
|
full.liquid
|
18
19
|
half_horizontal.liquid
|
19
20
|
half_vertical.liquid
|
20
21
|
quadrant.liquid
|
21
|
-
|
22
|
+
settings.yml
|
22
23
|
```
|
23
24
|
|
24
|
-
|
25
|
+
## Syncing Plugin With TRMNL Server
|
25
26
|
|
26
|
-
|
27
|
+
```sh
|
28
|
+
trmnl login # authenticate with TRMNL account
|
29
|
+
trmnl pull [id] # download (plugin ID required on first pull only)
|
30
|
+
trmnl push # upload
|
31
|
+
```
|
27
32
|
|
28
33
|
## Running the Server (Docker)
|
29
34
|
|
@@ -31,7 +36,7 @@ The [trmnl-hello](https://github.com/schrockwell/trmnl-hello) repository is prov
|
|
31
36
|
docker run \
|
32
37
|
-p 4567:4567 \
|
33
38
|
-v /path/to/plugin/on/host:/plugin \
|
34
|
-
|
39
|
+
trmnl/trmnlp
|
35
40
|
```
|
36
41
|
|
37
42
|
## Running the Server (Local Ruby)
|
@@ -43,29 +48,53 @@ Prerequisites:
|
|
43
48
|
- Firefox
|
44
49
|
- ImageMagick
|
45
50
|
|
46
|
-
In the plugin
|
51
|
+
In the plugin project:
|
47
52
|
|
48
53
|
```sh
|
49
54
|
gem install trmnl_preview
|
50
|
-
trmnlp serve
|
55
|
+
trmnlp serve
|
51
56
|
```
|
52
57
|
|
53
|
-
##
|
58
|
+
## `./.trmnlp.yml` Reference (Project Config)
|
59
|
+
|
60
|
+
The `.trmnlp.yml` file lives in the root of the plugin project, and is for configuring the local dev server.
|
61
|
+
|
62
|
+
System environment variables are made available in the `{{ env }}` Liquid varible in this file only. This can be used to safely
|
63
|
+
supply plugin secrets, like API keys.
|
64
|
+
|
65
|
+
All fields are optional.
|
54
66
|
|
55
|
-
|
67
|
+
```yaml
|
68
|
+
# {{ env.VARIABLE }} interpolation is available here
|
69
|
+
---
|
70
|
+
# auto-reload when files change (`watch: false` to disable)
|
71
|
+
watch:
|
72
|
+
- src
|
73
|
+
- .trmnlp.yml
|
74
|
+
|
75
|
+
# values of custom fields (defined in src/settings.yml)
|
76
|
+
custom_fields:
|
77
|
+
station: "{{ env.ICAO }}"
|
78
|
+
|
79
|
+
# override variables
|
80
|
+
variables:
|
81
|
+
trmnl:
|
82
|
+
user:
|
83
|
+
name: Peter Quill
|
84
|
+
plugin_settings:
|
85
|
+
instance_name: Kevin Bacon Facts
|
86
|
+
|
87
|
+
```
|
56
88
|
|
57
|
-
|
89
|
+
## `./src/settings.yml` Reference (Plugin Config)
|
58
90
|
|
59
|
-
|
91
|
+
The `settings.yml` file is part of the plugin definition.
|
60
92
|
|
61
|
-
|
62
|
-
- `url` - The URL from which to fetch JSON data (polling strategy only)
|
63
|
-
- `live_render` - Set to `false` to disable automatic rendering when Liquid templates change (default `true`)
|
64
|
-
- `[polling_headers]` - A section of headers to append to the HTTP poll request (polling strategy only)
|
93
|
+
See [TRMNL documentation](https://help.usetrmnl.com/en/articles/10542599-importing-and-exporting-private-plugins#h_581fb988f0) for details on this file's contents.
|
65
94
|
|
66
95
|
## Contributing
|
67
96
|
|
68
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
97
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/usetrmnl/trmnlp.
|
69
98
|
|
70
99
|
## License
|
71
100
|
|
data/bin/trmnlp
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday/multipart'
|
3
|
+
|
4
|
+
require_relative 'config'
|
5
|
+
|
6
|
+
module TRMNLP
|
7
|
+
class APIClient
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_plugin_setting_archive(id)
|
13
|
+
response = conn.get("plugin_settings/#{id}/archive")
|
14
|
+
|
15
|
+
if response.status == 200
|
16
|
+
temp_file = Tempfile.new(["plugin_settings_#{id}", '.zip'])
|
17
|
+
temp_file.binmode
|
18
|
+
temp_file.write(response.body)
|
19
|
+
temp_file.rewind
|
20
|
+
|
21
|
+
# return the path to the temp file
|
22
|
+
Pathname.new(temp_file.path)
|
23
|
+
else
|
24
|
+
raise Error, "failed to download plugin settings archive: #{response.status} #{response.body}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def post_plugin_setting_archive(id, path)
|
29
|
+
payload = {
|
30
|
+
file: Faraday::Multipart::FilePart.new(path, 'application/zip')
|
31
|
+
}
|
32
|
+
|
33
|
+
response = conn.post("plugin_settings/#{id}/archive", payload)
|
34
|
+
|
35
|
+
if response.status == 200
|
36
|
+
true
|
37
|
+
else
|
38
|
+
raise Error, "failed to upload plugin settings archive: #{response.status} #{response.body}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :config
|
45
|
+
|
46
|
+
def api_uri = config.app.api_uri
|
47
|
+
|
48
|
+
def conn
|
49
|
+
@conn ||= Faraday.new(url: api_uri, headers:) do |f|
|
50
|
+
f.request :multipart
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def headers
|
56
|
+
{
|
57
|
+
'Authorization' => "Bearer #{config.app.api_key}",
|
58
|
+
'User-Agent' => "trmnlp/#{VERSION}",
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -6,7 +6,7 @@ require 'sinatra/base'
|
|
6
6
|
require_relative 'context'
|
7
7
|
require_relative 'screen_generator'
|
8
8
|
|
9
|
-
module
|
9
|
+
module TRMNLP
|
10
10
|
class App < Sinatra::Base
|
11
11
|
# Sinatra settings
|
12
12
|
set :views, File.join(File.dirname(__FILE__), '..', '..', 'web', 'views')
|
@@ -15,25 +15,28 @@ module TRMNLPreview
|
|
15
15
|
def initialize(*args)
|
16
16
|
super
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
puts e.message
|
22
|
-
exit 1
|
23
|
-
end
|
18
|
+
@context = settings.context
|
19
|
+
|
20
|
+
@context.poll_data
|
24
21
|
|
25
|
-
@context.
|
22
|
+
@context.start_filewatcher if @context.config.project.live_render?
|
26
23
|
|
27
24
|
@live_reload_clients = []
|
28
|
-
@context.on_view_change do |view|
|
25
|
+
@context.on_view_change do |view, user_data|
|
29
26
|
@live_reload_clients.each do |ws|
|
30
|
-
|
27
|
+
payload = {
|
28
|
+
'type' => 'reload',
|
29
|
+
'view' => view,
|
30
|
+
'user_data' => user_data
|
31
|
+
}
|
32
|
+
|
33
|
+
ws.send(payload.to_json)
|
31
34
|
end
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
35
38
|
post '/webhook' do
|
36
|
-
@context.
|
39
|
+
@context.put_webhook(request.body.read)
|
37
40
|
"OK"
|
38
41
|
end
|
39
42
|
|
@@ -41,6 +44,11 @@ module TRMNLPreview
|
|
41
44
|
redirect '/full'
|
42
45
|
end
|
43
46
|
|
47
|
+
get '/data' do
|
48
|
+
content_type :json
|
49
|
+
JSON.pretty_generate(@context.user_data)
|
50
|
+
end
|
51
|
+
|
44
52
|
get '/live_reload' do
|
45
53
|
ws = Faye::WebSocket.new(request.env)
|
46
54
|
|
@@ -63,12 +71,16 @@ module TRMNLPreview
|
|
63
71
|
VIEWS.each do |view|
|
64
72
|
get "/#{view}" do
|
65
73
|
@view = view
|
66
|
-
@
|
74
|
+
@user_data = JSON.pretty_generate(@context.user_data)
|
75
|
+
@live_reload = @context.config.project.live_render?
|
76
|
+
|
67
77
|
erb :index
|
68
78
|
end
|
69
79
|
|
70
80
|
get "/render/#{view}.html" do
|
71
81
|
@view = view
|
82
|
+
@screen_classes = @context.screen_classes
|
83
|
+
|
72
84
|
erb :render_html do
|
73
85
|
@context.render_template(view)
|
74
86
|
end
|
data/lib/trmnlp/cli.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
require_relative '../trmnlp'
|
4
|
+
require_relative '../trmnlp/commands'
|
5
|
+
|
6
|
+
module TRMNLP
|
7
|
+
class CLI < Thor
|
8
|
+
package_name 'trmnlp'
|
9
|
+
|
10
|
+
class_option :dir, type: :string, default: Dir.pwd, aliases: '-d',
|
11
|
+
desc: 'Plugin directory'
|
12
|
+
|
13
|
+
def self.exit_on_failure? = true
|
14
|
+
|
15
|
+
desc 'build', 'Generate static HTML files'
|
16
|
+
def build
|
17
|
+
Commands::Build.new(options).call
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'login', 'Authenticate with TRMNL server'
|
21
|
+
def login
|
22
|
+
Commands::Login.new(options).call
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'pull [id]', 'Download plugin settings from TRMNL server'
|
26
|
+
method_option :force, type: :boolean, default: false, aliases: '-f',
|
27
|
+
desc: 'Skip confirmation prompts'
|
28
|
+
def pull(plugin_settings_id = nil)
|
29
|
+
Commands::Pull.new(options).call(plugin_settings_id)
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'push [id]', 'Upload plugin settings to TRMNL server'
|
33
|
+
method_option :force, type: :boolean, default: false, aliases: '-f',
|
34
|
+
desc: 'Skip confirmation prompts'
|
35
|
+
def push(plugin_settings_id = nil)
|
36
|
+
Commands::Push.new(options).call(plugin_settings_id)
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'serve', 'Start a local dev server'
|
40
|
+
method_option :bind, type: :string, default: '127.0.0.1', aliases: '-b', desc: 'Bind address'
|
41
|
+
method_option :port, type: :numeric, default: 4567, aliases: '-p', desc: 'Port number'
|
42
|
+
def serve
|
43
|
+
Commands::Serve.new(options).call
|
44
|
+
end
|
45
|
+
|
46
|
+
desc 'version', 'Show version'
|
47
|
+
def version
|
48
|
+
puts VERSION
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative '../context'
|
2
|
+
|
3
|
+
module TRMNLP
|
4
|
+
module Commands
|
5
|
+
class Base
|
6
|
+
def initialize(options)
|
7
|
+
@options = options
|
8
|
+
@context = Context.new(options.dir)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_accessor :options, :context
|
18
|
+
|
19
|
+
def config = context.config
|
20
|
+
def paths = context.paths
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module TRMNLP
|
4
|
+
module Commands
|
5
|
+
class Build < Base
|
6
|
+
def call
|
7
|
+
context = Context.new(options.dir)
|
8
|
+
context.validate!
|
9
|
+
context.poll_data
|
10
|
+
context.paths.create_build_dir
|
11
|
+
|
12
|
+
VIEWS.each do |view|
|
13
|
+
output_path = context.paths.build_dir.join("#{view}.html")
|
14
|
+
puts "Writing #{output_path}..."
|
15
|
+
output_path.write(context.render_full_page(view))
|
16
|
+
end
|
17
|
+
|
18
|
+
puts "Done!"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module TRMNLP
|
4
|
+
module Commands
|
5
|
+
class Login < Base
|
6
|
+
def call
|
7
|
+
if config.app.logged_in?
|
8
|
+
anonymous_key = config.app.api_key[0..10] + '*' * (config.app.api_key.length - 11)
|
9
|
+
puts "Currently authenticated as: #{anonymous_key}"
|
10
|
+
end
|
11
|
+
|
12
|
+
puts "Please visit #{config.app.account_uri} to grab your API key, then paste it here."
|
13
|
+
|
14
|
+
print "API Key: "
|
15
|
+
api_key = STDIN.gets.chomp
|
16
|
+
raise Error, "API key cannot be empty" if api_key.empty?
|
17
|
+
|
18
|
+
config.app.api_key = api_key
|
19
|
+
config.app.save
|
20
|
+
|
21
|
+
puts "Saved changes to #{paths.app_config}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'zip'
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
require_relative '../api_client'
|
5
|
+
|
6
|
+
module TRMNLP
|
7
|
+
module Commands
|
8
|
+
class Pull < Base
|
9
|
+
def call(plugin_settings_id)
|
10
|
+
context.validate!
|
11
|
+
|
12
|
+
raise Error, "please run `trmnlp login`" unless config.app.logged_in?
|
13
|
+
|
14
|
+
plugin_settings_id ||= config.plugin.id
|
15
|
+
raise Error, 'plugin ID must be specified' if plugin_settings_id.nil?
|
16
|
+
|
17
|
+
unless options.force
|
18
|
+
print "Local plugin files will be overwritten. Are you sure? (y/n) "
|
19
|
+
answer = $stdin.gets.chomp.downcase
|
20
|
+
raise Error, 'aborting' unless answer == 'y' || answer == 'yes'
|
21
|
+
end
|
22
|
+
|
23
|
+
api = APIClient.new(config)
|
24
|
+
temp_path = api.get_plugin_setting_archive(plugin_settings_id)
|
25
|
+
size = 0
|
26
|
+
|
27
|
+
begin
|
28
|
+
Zip::File.open(temp_path) do |zip_file|
|
29
|
+
zip_file.each do |entry|
|
30
|
+
dest_path = paths.src_dir.join(entry.name)
|
31
|
+
dest_path.dirname.mkpath
|
32
|
+
zip_file.extract(entry, dest_path) { true } # overwrite existing
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
size = File.size(temp_path)
|
37
|
+
ensure
|
38
|
+
temp_path.delete
|
39
|
+
end
|
40
|
+
|
41
|
+
puts "Downloaded plugin (#{size} bytes)"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'zip'
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
require_relative '../api_client'
|
5
|
+
|
6
|
+
module TRMNLP
|
7
|
+
module Commands
|
8
|
+
class Push < Base
|
9
|
+
def call(plugin_settings_id)
|
10
|
+
context.validate!
|
11
|
+
|
12
|
+
raise Error, "please run `trmnlp login`" unless config.app.logged_in?
|
13
|
+
|
14
|
+
plugin_settings_id ||= config.plugin.id
|
15
|
+
raise Error, 'plugin ID must be specified' if plugin_settings_id.nil?
|
16
|
+
|
17
|
+
unless options.force
|
18
|
+
print "Plugin settings on the server will be overwritten. Are you sure? (y/n) "
|
19
|
+
answer = $stdin.gets.chomp.downcase
|
20
|
+
raise Error, 'aborting' unless answer == 'y' || answer == 'yes'
|
21
|
+
end
|
22
|
+
|
23
|
+
api = APIClient.new(config)
|
24
|
+
size = 0
|
25
|
+
|
26
|
+
Tempfile.create(binmode: true) do |temp_file|
|
27
|
+
Zip::File.open(temp_file.path, Zip::File::CREATE) do |zip_file|
|
28
|
+
paths.src_files.each do |file|
|
29
|
+
zip_file.add(File.basename(file), file)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
api.post_plugin_setting_archive(plugin_settings_id, temp_file.path)
|
34
|
+
|
35
|
+
size = File.size(temp_file.path)
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
puts "Uploaded plugin (#{size} bytes)"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'zip'
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
require_relative '../api_client'
|
5
|
+
|
6
|
+
module TRMNLP
|
7
|
+
module Commands
|
8
|
+
class Serve < Base
|
9
|
+
def call
|
10
|
+
context.validate!
|
11
|
+
|
12
|
+
# Must come AFTER parsing options
|
13
|
+
require_relative '../app'
|
14
|
+
|
15
|
+
# Now we can configure things
|
16
|
+
App.set(:context, context)
|
17
|
+
App.set(:bind, options.bind)
|
18
|
+
App.set(:port, options.port)
|
19
|
+
|
20
|
+
# Finally, start the app!
|
21
|
+
App.run!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Dir[File.join(__dir__, 'commands', '*.rb')].each { |file| require file }
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module TRMNLP
|
4
|
+
class Config
|
5
|
+
# Stores trmnlp-wide configuration (irrespective of the current plugin)
|
6
|
+
class App
|
7
|
+
def initialize(paths)
|
8
|
+
@paths = paths
|
9
|
+
@config = read_config
|
10
|
+
end
|
11
|
+
|
12
|
+
def save
|
13
|
+
paths.app_config_dir.mkpath
|
14
|
+
paths.app_config.write(YAML.dump(@config))
|
15
|
+
end
|
16
|
+
|
17
|
+
def logged_in? = api_key && !api_key.empty?
|
18
|
+
def logged_out? = !logged_in?
|
19
|
+
|
20
|
+
def api_key = @config['api_key']
|
21
|
+
|
22
|
+
def api_key=(key)
|
23
|
+
@config['api_key'] = key
|
24
|
+
end
|
25
|
+
|
26
|
+
def base_uri = URI.parse(@config['base_url'] || 'https://usetrmnl.com')
|
27
|
+
|
28
|
+
def api_uri = URI.join(base_uri, 'api')
|
29
|
+
|
30
|
+
def account_uri = URI.join(base_uri, 'account')
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :paths
|
35
|
+
|
36
|
+
def read_config = paths.app_config.exist? ? YAML.safe_load(paths.app_config.read) : {}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module TRMNLP
|
4
|
+
class Config
|
5
|
+
class Plugin
|
6
|
+
def initialize(paths, trmnlp_config)
|
7
|
+
@paths = paths
|
8
|
+
@trmnlp_config = trmnlp_config
|
9
|
+
reload!
|
10
|
+
end
|
11
|
+
|
12
|
+
def reload!
|
13
|
+
if paths.plugin_config.exist?
|
14
|
+
@config = YAML.load_file(paths.plugin_config)
|
15
|
+
else
|
16
|
+
@config = {}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def strategy = @config['strategy']
|
21
|
+
def polling? = strategy == 'polling'
|
22
|
+
def webhook? = strategy == 'webhook'
|
23
|
+
def static? = strategy == 'static'
|
24
|
+
|
25
|
+
def polling_urls
|
26
|
+
return [] if @config['polling_url'].nil? || @config['polling_url'].empty?
|
27
|
+
|
28
|
+
urls = @config['polling_url'].split("\n").map(&:strip)
|
29
|
+
|
30
|
+
urls.map { |url| with_custom_fields(url) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def polling_url_text = polling_urls.join("\r\n") # for {{ trmnl }}
|
34
|
+
|
35
|
+
def polling_verb = @config['polling_verb'] || 'GET'
|
36
|
+
|
37
|
+
def polling_headers
|
38
|
+
string_to_hash(@config['polling_headers'] || '').transform_values { |v| with_custom_fields(v) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def polling_headers_encoded = polling_headers.map { |k, v| "#{k}=#{v}" }.join('&') # for {{ trmnl }}
|
42
|
+
|
43
|
+
def polling_body = with_custom_fields(@config['polling_body'] || '')
|
44
|
+
|
45
|
+
def dark_mode = @config['dark_mode'] || 'no'
|
46
|
+
|
47
|
+
def no_screen_padding = @config['no_screen_padding'] || 'no'
|
48
|
+
|
49
|
+
def id = @config['id']
|
50
|
+
|
51
|
+
def static_data
|
52
|
+
JSON.parse(@config['static_data'] || '{}')
|
53
|
+
rescue JSON::ParserError
|
54
|
+
raise Error, 'invalid JSON in static_data'
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
attr_reader :paths, :trmnlp_config
|
60
|
+
|
61
|
+
def with_custom_fields(value) = trmnlp_config.with_custom_fields(value)
|
62
|
+
|
63
|
+
# copied from TRMNL core
|
64
|
+
def string_to_hash(str, delimiter: '=')
|
65
|
+
str.split('&').map do |k_v|
|
66
|
+
key, value = k_v.split(delimiter)
|
67
|
+
next if value.nil?
|
68
|
+
|
69
|
+
{ key => CGI.unescape_uri_component(value) }
|
70
|
+
end.compact.reduce({}, :merge)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|