terminalwire-server 0.3.0.alpha1
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 +7 -0
- data/lib/terminalwire/server/context.rb +80 -0
- data/lib/terminalwire/server/resource.rb +120 -0
- data/lib/terminalwire/server/thor.rb +69 -0
- data/lib/terminalwire/server.rb +27 -0
- data/lib/terminalwire-server.rb +3 -0
- metadata +81 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6478b8cc01d3c36333ca938f647700798e211487fd6a4c076b91809348f8adaf
|
4
|
+
data.tar.gz: 5bf273aeb4f3cf36df8b4af47e78b96761daf2be32f6fc31945c6beb4bc235e9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f6793ba99120adaef93ae16bbe9b71f38213f426bf3765ff19bea8d47fa7c5784df7d9c42c7e338769aa29ad9b3ae466cb961446f3cdaa77c6680429cfa4469
|
7
|
+
data.tar.gz: c0bbf7cb3d28d0a97893ad7befcf5b39404bdef47d55a7074cbfa6d1e3401466fd1b887d6ea46347b6b42050015568c3177b0d3bb66afd477b0a88d213fe692d
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
module Terminalwire::Server
|
4
|
+
# Contains all of the resources that are accessible to the server on the client-side.
|
5
|
+
# It's the primary interface for the server to interact with the client and is integrated
|
6
|
+
# into other libraries like Thor, etc.
|
7
|
+
class Context
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
attr_reader \
|
11
|
+
:stdout, :stdin, :stderr,
|
12
|
+
:browser,
|
13
|
+
:file, :directory,
|
14
|
+
:environment_variable,
|
15
|
+
:authority,
|
16
|
+
:root_path,
|
17
|
+
:authority_path,
|
18
|
+
:storage_path
|
19
|
+
|
20
|
+
def_delegators :@stdout, :puts, :print
|
21
|
+
def_delegators :@stdin, :gets, :getpass
|
22
|
+
|
23
|
+
def initialize(adapter:, entitlement:)
|
24
|
+
@adapter = adapter
|
25
|
+
@entitlement = entitlement
|
26
|
+
|
27
|
+
# Initialize resources
|
28
|
+
@stdout = Resource::STDOUT.new("stdout", @adapter)
|
29
|
+
@stdin = Resource::STDIN.new("stdin", @adapter)
|
30
|
+
@stderr = Resource::STDERR.new("stderr", @adapter)
|
31
|
+
@browser = Resource::Browser.new("browser", @adapter)
|
32
|
+
@file = Resource::File.new("file", @adapter)
|
33
|
+
@directory = Resource::Directory.new("directory", @adapter)
|
34
|
+
@environment_variable = Resource::EnvironmentVariable.new("environment_variable", @adapter)
|
35
|
+
|
36
|
+
# Authority is provided by the client.
|
37
|
+
@authority = @entitlement.fetch(:authority)
|
38
|
+
# The Terminalwire home path is provided by the client and set
|
39
|
+
# as an environment variable.
|
40
|
+
@root_path = Pathname.new(
|
41
|
+
@environment_variable.read("TERMINALWIRE_HOME")
|
42
|
+
)
|
43
|
+
# Now derive the rest of the paths from the Terminalwire home path.
|
44
|
+
@authority_path = @root_path.join("authorities", @authority)
|
45
|
+
@storage_path = @authority_path.join("storage")
|
46
|
+
|
47
|
+
if block_given?
|
48
|
+
begin
|
49
|
+
yield self
|
50
|
+
ensure
|
51
|
+
exit
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Wraps the environment variables in a hash-like object that can be accessed
|
57
|
+
# from client#ENV. This makes it look and feel just like the ENV object in Ruby.
|
58
|
+
class Env
|
59
|
+
def initialize(context:)
|
60
|
+
@context = context
|
61
|
+
end
|
62
|
+
|
63
|
+
def [](name)
|
64
|
+
@context.environment_variable.read(name)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def ENV
|
69
|
+
@ENV ||= Env.new(context: self)
|
70
|
+
end
|
71
|
+
|
72
|
+
def exit(status = 0)
|
73
|
+
@adapter.write(event: "exit", status: status)
|
74
|
+
end
|
75
|
+
|
76
|
+
def close
|
77
|
+
@adapter.close
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module Terminalwire::Server
|
2
|
+
# Representation of the resources avilable to the server on the client-side. These
|
3
|
+
# classes encapsulate the API alls to the client and provide a more Ruby-like interface.
|
4
|
+
module Resource
|
5
|
+
class Base < Terminalwire::Resource::Base
|
6
|
+
private
|
7
|
+
|
8
|
+
def command(command, **parameters)
|
9
|
+
@adapter.write(
|
10
|
+
event: "resource",
|
11
|
+
name: @name,
|
12
|
+
action: "command",
|
13
|
+
command: command,
|
14
|
+
parameters: parameters
|
15
|
+
)
|
16
|
+
|
17
|
+
response = @adapter.read
|
18
|
+
case response.fetch(:status)
|
19
|
+
when "success"
|
20
|
+
response.fetch(:response)
|
21
|
+
when "failure"
|
22
|
+
raise Terminalwire::Error, response.inspect
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class EnvironmentVariable < Base
|
28
|
+
# Accepts a list of environment variables to permit.
|
29
|
+
def read(name)
|
30
|
+
command("read", name:)
|
31
|
+
end
|
32
|
+
|
33
|
+
# def write(name:, value:)
|
34
|
+
# command("write", name:, value:)
|
35
|
+
# end
|
36
|
+
end
|
37
|
+
|
38
|
+
class STDOUT < Base
|
39
|
+
def puts(data)
|
40
|
+
command("print_line", data: data)
|
41
|
+
end
|
42
|
+
|
43
|
+
def print(data)
|
44
|
+
command("print", data: data)
|
45
|
+
end
|
46
|
+
|
47
|
+
def flush
|
48
|
+
# Do nothing
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class STDERR < STDOUT
|
53
|
+
end
|
54
|
+
|
55
|
+
class STDIN < Base
|
56
|
+
def getpass
|
57
|
+
command("read_password")
|
58
|
+
end
|
59
|
+
|
60
|
+
def gets
|
61
|
+
command("read_line")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class File < Base
|
66
|
+
def read(path)
|
67
|
+
command("read", path: path.to_s)
|
68
|
+
end
|
69
|
+
|
70
|
+
def write(path, content)
|
71
|
+
command("write", path: path.to_s, content:)
|
72
|
+
end
|
73
|
+
|
74
|
+
def append(path, content)
|
75
|
+
command("append", path: path.to_s, content:)
|
76
|
+
end
|
77
|
+
|
78
|
+
def delete(path)
|
79
|
+
command("delete", path: path.to_s)
|
80
|
+
end
|
81
|
+
alias :rm :delete
|
82
|
+
|
83
|
+
def exist?(path)
|
84
|
+
command("exist", path: path.to_s)
|
85
|
+
end
|
86
|
+
|
87
|
+
def change_mode(path, mode)
|
88
|
+
command("change_mode", path: path.to_s, mode:)
|
89
|
+
end
|
90
|
+
alias :chmod :change_mode
|
91
|
+
end
|
92
|
+
|
93
|
+
class Directory < Base
|
94
|
+
def list(path)
|
95
|
+
command("list", path: path.to_s)
|
96
|
+
end
|
97
|
+
alias :ls :list
|
98
|
+
|
99
|
+
def create(path)
|
100
|
+
command("create", path: path.to_s)
|
101
|
+
end
|
102
|
+
alias :mkdir :create
|
103
|
+
|
104
|
+
def exist?(path)
|
105
|
+
command("exist", path: path.to_s)
|
106
|
+
end
|
107
|
+
|
108
|
+
def delete(path)
|
109
|
+
command("delete", path: path.to_s)
|
110
|
+
end
|
111
|
+
alias :rm :delete
|
112
|
+
end
|
113
|
+
|
114
|
+
class Browser < Base
|
115
|
+
def launch(url)
|
116
|
+
command("launch", url: url)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module Terminalwire
|
4
|
+
module Server
|
5
|
+
module Thor
|
6
|
+
class Shell < ::Thor::Shell::Basic
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
# Encapsulates all of the IO resources for a Terminalwire adapter.
|
10
|
+
attr_reader :context, :session
|
11
|
+
|
12
|
+
def_delegators :context,
|
13
|
+
:stdin, :stdout, :stderr
|
14
|
+
|
15
|
+
def initialize(context, *, **, &)
|
16
|
+
@context = context
|
17
|
+
@session = Terminalwire::Rails::Session.new(context:)
|
18
|
+
super(*,**,&)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.included(base)
|
23
|
+
base.extend ClassMethods
|
24
|
+
|
25
|
+
# I have to do this in a block to deal with some of Thor's DSL
|
26
|
+
base.class_eval do
|
27
|
+
extend Forwardable
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
no_commands do
|
32
|
+
def_delegators :shell,
|
33
|
+
:context, :session
|
34
|
+
def_delegators :context,
|
35
|
+
:stdout, :stdin, :stderr, :browser
|
36
|
+
def_delegators :stdout,
|
37
|
+
:puts, :print
|
38
|
+
def_delegators :stdin,
|
39
|
+
:gets, :getpass
|
40
|
+
|
41
|
+
# Prints text to the standard error stream.
|
42
|
+
def warn(...)
|
43
|
+
stderr.puts(...)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Prints text to the standard error stream and exits the program.
|
47
|
+
def fail(...)
|
48
|
+
stderr.puts(...)
|
49
|
+
context.exit 1
|
50
|
+
ensure
|
51
|
+
super
|
52
|
+
end
|
53
|
+
# Feels more naturual to call `client.files` etc. from
|
54
|
+
# the serve since it's more apparent that it's a client.
|
55
|
+
alias :client :context
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module ClassMethods
|
61
|
+
def start(given_args = ARGV, config = {})
|
62
|
+
context = config.delete(:context)
|
63
|
+
config[:shell] = Shell.new(context) if context
|
64
|
+
super(given_args, config)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "terminalwire"
|
2
|
+
require "terminalwire/logging"
|
3
|
+
|
4
|
+
require "zeitwerk"
|
5
|
+
Zeitwerk::Loader.for_gem_extension(Terminalwire).tap do |loader|
|
6
|
+
loader.setup
|
7
|
+
end
|
8
|
+
|
9
|
+
module Terminalwire
|
10
|
+
module Server
|
11
|
+
class WebSocket
|
12
|
+
include Logging
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
Async::WebSocket::Adapters::Rack.open(env, protocols: ['ws']) do |connection|
|
16
|
+
handle(Adapter::Socket.new(Terminalwire::Transport::WebSocket.new(connection)))
|
17
|
+
end or [200, { "Content-Type" => "text/plain" }, ["Connect via WebSockets"]]
|
18
|
+
end
|
19
|
+
|
20
|
+
def handle(adapter)
|
21
|
+
while message = adapter.read
|
22
|
+
puts message
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: terminalwire-server
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0.alpha1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brad Gessler
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-12-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: terminalwire-core
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.0.alpha1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.3.0.alpha1
|
41
|
+
description: Stream command-line apps from your server without a web API
|
42
|
+
email:
|
43
|
+
- brad@terminalwire.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- lib/terminalwire-server.rb
|
49
|
+
- lib/terminalwire/server.rb
|
50
|
+
- lib/terminalwire/server/context.rb
|
51
|
+
- lib/terminalwire/server/resource.rb
|
52
|
+
- lib/terminalwire/server/thor.rb
|
53
|
+
homepage: https://terminalwire.com/ruby
|
54
|
+
licenses:
|
55
|
+
- Proprietary (https://terminalwire.com/license)
|
56
|
+
metadata:
|
57
|
+
allowed_push_host: https://rubygems.org/
|
58
|
+
homepage_uri: https://terminalwire.com/ruby
|
59
|
+
source_code_uri: https://github.com/terminalwire/ruby/tree/main/terminalwire-server
|
60
|
+
changelog_uri: https://github.com/terminalwire/ruby/tags
|
61
|
+
funding_uri: https://terminalwire.com/funding
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 3.0.0
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
requirements: []
|
77
|
+
rubygems_version: 3.5.9
|
78
|
+
signing_key:
|
79
|
+
specification_version: 4
|
80
|
+
summary: Ship a CLI for your web app. No API required.
|
81
|
+
test_files: []
|