evolis-premium_sdk 1.0.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.
@@ -0,0 +1,76 @@
1
+ require 'evolis/premium_sdk/sdk_base'
2
+
3
+ module Evolis
4
+ module PremiumSdk
5
+ class Espf < SdkBase
6
+
7
+ # Initializes the class and sets SDK host and port
8
+ #
9
+ # @param host [String] host or IP for SDK
10
+ # @param port [String, Fixnum] port for SDK
11
+ def initialize(host, port)
12
+ super(host, port, 'ESPF')
13
+ end
14
+
15
+ # Reads the value of a server parameter
16
+ #
17
+ # @param key [String] ESPF service parameter
18
+ # @return [String] current value
19
+ # @raise [Error::InvalidParamError] if the parameters supplied is not valid
20
+ def get_param(key)
21
+ raise Error::InvalidParamError.new key unless valid_param?(key)
22
+
23
+ call_rpc('GetParam', {
24
+ key: key
25
+ })
26
+ end
27
+
28
+ # Edits the value of server parameter
29
+ #
30
+ # @param key [String] ESPF service parameter
31
+ # @param value [String] value to be set
32
+ # @return [true] if set as planned
33
+ # @raise [Error::InvalidParamError] if the parameters supplied is not valid
34
+ def set_param(key, value)
35
+ raise Error::InvalidParamError.new "#{key}=#{value}" unless valid_param?(key, value)
36
+
37
+ call_rpc('SetParam', {
38
+ key: key,
39
+ data: value
40
+ })
41
+ end
42
+
43
+ # Checks if the parameters supplied is valid
44
+ #
45
+ # @param key [String] ESPF service parameter
46
+ # @param value [nil, false, String] nil/false when parameter only, String to run check on value
47
+ # @return [true, false] true when validation succeeds and false when it does not
48
+ def valid_param?(key, value = nil)
49
+ params = value ? WRITE_PARAMS : READ_PARAMS.merge(WRITE_PARAMS)
50
+
51
+ return false unless params.has_key?(key.to_sym)
52
+
53
+ if value
54
+ return false if value.is_a?(String) && value.empty?
55
+ return false if params[key.to_sym].is_a?(Array) && !params[key.to_sym].include?(value)
56
+ return false if params[key.to_sym].is_a?(Regexp) && value !~ params[key.to_sym]
57
+ end
58
+
59
+ return true
60
+ end
61
+
62
+ # Parameters and values valid for setting
63
+ WRITE_PARAMS = {
64
+ 'ESPFServerManager.port': /^[1-9][0-9]+$/,
65
+ 'ESPFTcpServerConnectionSupervisor.receivetimeout': /^[1-9][0-9]*$/,
66
+ 'ESPFServerManager.tcpenabled': %w[true false]
67
+ }
68
+
69
+ # Parameters valid for reading
70
+ READ_PARAMS = {
71
+ 'ESPFService.version': true,
72
+ 'ESPFService.requestlanguageversion': true
73
+ }
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,95 @@
1
+ require 'evolis/premium_sdk/sdk_base'
2
+
3
+ module Evolis
4
+ module PremiumSdk
5
+ class Print < SdkBase
6
+
7
+ # Initializes the class and sets SDK host and port
8
+ #
9
+ # @param host [String] host or IP for SDK
10
+ # @param port [String, Fixnum] port for SDK
11
+ def initialize(host, port)
12
+ super(host, port, 'PRINT')
13
+ end
14
+
15
+ # Initiates a printing session
16
+ #
17
+ # @param device [String] printer name
18
+ # @return [String] session id
19
+ def begin(device)
20
+ self.active_session = call_rpc('Begin', {
21
+ device: device
22
+ })
23
+ end
24
+
25
+ # Sets the printing parameters
26
+ #
27
+ # @param data [String, Array] print settings as "setting=value;setting2=value2"
28
+ # or ["setting=value","setting2"="value2"]
29
+ # @return [true] if set successful
30
+ # @raise [Error::NoActiveSessionError] if no active session
31
+ # @raise [Error::InvalidPrintSettingError] on invalid print settings
32
+ def set(data)
33
+ raise Error::NoActiveSessionError.new unless active_session?
34
+ raise Error::InvalidPrintSettingError.new data unless valid_settings?(data)
35
+
36
+ data = data.join(';') if data.is_a?(Array)
37
+ call_rpc('Set', {
38
+ session: self.active_session,
39
+ data: data
40
+ })
41
+ end
42
+
43
+ # Defines the graphic data to be printed
44
+ # @note Can only be run once per card side and panel type
45
+ #
46
+ # @param data [String] base64 encoded bitmap information, must start with `base64`
47
+ # @param face [String] card face to print on, `front` or `back`
48
+ # @param panel [String] panel type to print, `color`, `resin` or `varnish`
49
+ # @return [true] if added successful
50
+ # @raise [Error::NoActiveSessionError] if no active session
51
+ # @raise [Error::NoSuchFaceError] when face is not recognized
52
+ # @raise [Error::NoSuchPanelError] on unknown panel type
53
+ # @raise [Error::Base64FormatError] if data does not validate to base64 format
54
+ def set_bitmap(data, face = 'front', panel = 'color')
55
+ raise Error::NoActiveSessionError.new unless active_session?
56
+ raise Error::NoSuchFaceError.new face unless %w[front back].include?(face.downcase)
57
+ raise Error::NoSuchPanelError.new panel unless %w[color resin varnish].include?(panel.downcase)
58
+ raise Error::Base64FormatError.new data unless valid_base64?(data)
59
+
60
+ call_rpc('SetBitmap', {
61
+ session: self.active_session,
62
+ face: face,
63
+ panel: panel,
64
+ data: data
65
+ })
66
+ end
67
+
68
+ # Launches a printing job
69
+ # @note When calling the `print`, the `get_event` method from the `Supervision` service must be polled on a
70
+ # regular basis. If an event is identified, an action must be taken so that the print job can be finalized.
71
+ #
72
+ # @return [true] if started printing
73
+ # @raise [Error::NoActiveSessionError] if no active session
74
+ def print
75
+ raise Error::NoActiveSessionError.new unless active_session?
76
+
77
+ call_rpc('Print', {
78
+ session: self.active_session
79
+ })
80
+ end
81
+
82
+ # Ends the session
83
+ #
84
+ # @return [true] if ended session
85
+ # @raise [Error::NoActiveSessionError] if no active session
86
+ def end
87
+ raise Error::NoActiveSessionError.new unless active_session?
88
+
89
+ call_rpc('End', {
90
+ session: self.active_session
91
+ })
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,125 @@
1
+ require 'multi_json'
2
+ require 'socket'
3
+ require 'evolis/premium_sdk/error'
4
+
5
+ module Evolis
6
+ module PremiumSdk
7
+ class RpcClient
8
+ # JSON-RPC version number
9
+ JSON_RPC_VERSION = '2.0'
10
+
11
+ # @return [Hash] the last request made to the API
12
+ attr_reader :request
13
+
14
+ # @return [Hash] the last response from API
15
+ attr_reader :response
16
+
17
+ # @return [String] randomly generated number between 10 and 12 digits
18
+ def self.make_id
19
+ String rand(10**12)
20
+ end
21
+
22
+ # Initializes the class and sets API host and port
23
+ #
24
+ # @param host [String] host or IP for API
25
+ # @param port [String, Fixnum] port for API
26
+ def initialize(host, port)
27
+ @host = host
28
+ @port = port
29
+ end
30
+
31
+ # Make call to API and process response
32
+ #
33
+ # @param method [String] request method
34
+ # @param args [Hash, Array, String] data sent as request
35
+ # @return [Hash, Array, String] the data in the format received from server
36
+ # @raise [Error::InvalidJSON] if data from server is not valid JSON
37
+ def call(method, args)
38
+ resp = send_single_request(method.to_s, args)
39
+
40
+ begin
41
+ data = MultiJson.decode(resp)
42
+ rescue
43
+ raise Error::InvalidJSON.new(resp)
44
+ end
45
+
46
+ return process_single_response(data)
47
+
48
+ rescue Exception, StandardError => e
49
+ e.extend(Error) unless e.is_a?(Error)
50
+ raise e
51
+ end
52
+
53
+ # The method that does the actual sending of data to API
54
+ #
55
+ # @param method [String] request method
56
+ # @param args [Hash, Array, String] data sent as request
57
+ # @return [Hash] response from server in JSON format (Hash)
58
+ # @raise [Error::InvalidResponse] on empty response from server, or no response
59
+ def send_single_request(method, args)
60
+ @request = MultiJson.encode({
61
+ jsonrpc: JSON_RPC_VERSION,
62
+ method: method,
63
+ params: args,
64
+ id: self.class.make_id
65
+ })
66
+
67
+ begin
68
+ socket = TCPSocket.open(@host, @port)
69
+ socket.write(@request)
70
+ socket.close_write
71
+ resp = socket.read
72
+ ensure
73
+ socket.close if socket
74
+ end
75
+
76
+ raise Error::InvalidResponse.new if resp.nil? || resp.empty?
77
+
78
+ return @response = resp
79
+ end
80
+
81
+ # Process and validate response from API
82
+ #
83
+ # @param data [Hash] response from API
84
+ # @return [Hash, Array, String] from result key in response
85
+ # @raise [Error::InvalidResponse] if response does not validate
86
+ # @raise [Error::ServerError] on response with error key
87
+ def process_single_response(data)
88
+ raise Error::InvalidResponse.new unless valid_response?(data)
89
+
90
+ if !!data['error']
91
+ code = data['error']['code']
92
+ msg = data['error']['message']
93
+ raise Error::ServerError.new(code, msg)
94
+ end
95
+
96
+ return data['result']
97
+ end
98
+
99
+ # Validates tje response from API
100
+ #
101
+ # @param data [Hash] response from API
102
+ # @return [true, false] true if valid or false when invalid
103
+ def valid_response?(data)
104
+ return false unless data.is_a?(Hash)
105
+ return false if data['jsonrpc'] != JSON_RPC_VERSION
106
+ return false unless data.has_key?('id')
107
+ return false if data.has_key?('error') && data.has_key?('result')
108
+
109
+ if data.has_key?('error')
110
+ if !data['error'].is_a?(Hash) || !data['error'].has_key?('code') || !data['error'].has_key?('message')
111
+ return false
112
+ end
113
+
114
+ if !data['error']['code'].is_a?(Fixnum) || !data['error']['message'].is_a?(String)
115
+ return false
116
+ end
117
+ end
118
+
119
+ return true
120
+ rescue
121
+ return false
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,153 @@
1
+ require 'evolis/premium_sdk/rpc_client'
2
+
3
+ module Evolis
4
+ module PremiumSdk
5
+ class SdkBase
6
+ # @return [String] returns the active session
7
+ attr_accessor :active_session
8
+
9
+ # Initalizes the class, sets default options
10
+ #
11
+ # @param host [String] host or ip to Premium SDK API
12
+ # @param port [String, Fixnum] port to Premium SDK API
13
+ # @param service [String] servicename, used only internally (e.g. CMD or PRINT)
14
+ def initialize(host, port, service)
15
+ @rpc = RpcClient.new(host, port)
16
+ @service = service
17
+ end
18
+
19
+ # Makes the call to the API and returns results
20
+ #
21
+ # @param method [String] method name for the service
22
+ # @param args [String] arguments and parameters to send to service
23
+ # @return [String] returns result parameter from the response
24
+ # @return [true] if result is "OK"
25
+ def call_rpc(method, args)
26
+ method = sanitize_parameters(method)
27
+ args = sanitize_parameters(args)
28
+ resp = @rpc.call("#{@service}.#{method}", args)
29
+
30
+ return true if resp == 'OK'
31
+ return resp
32
+ end
33
+
34
+ # Method to lookup the full response
35
+ # @return [Hash] full json response
36
+ # @return [nil] before first response
37
+ def response
38
+ @rpc.response
39
+ end
40
+
41
+ # Method to lookup the full request
42
+ # @return [Hash] full json request
43
+ # @return (nil) before first request
44
+ def request
45
+ @rpc.request
46
+ end
47
+
48
+ # Settings and their values allowed to be used when getting and setting settings for print
49
+ SETTINGS = {
50
+ GDuplexMode: %w[SIMPLEX DUPLEX_CC DUPLEX_CM DUPLEX_MC DUPLEX_MM],
51
+ GInputTray: %w[FEEDER AUTO MANUAL PRINTER],
52
+ GOutputTray: %w[HOPPER REAR PRINTER],
53
+ GRejectBox: %w[DEFAULTREJECT HOPPER PRINTER],
54
+ GRibbonType: %w[RC_YMCKO RC_YMCKOS RC_YMCKOK RC_YMCKOKOS RM_KO RM_KBLACK RM_KWHITE RM_KRED RM_KGREEN RM_KBLUE RM_KSCRATCH RM_KMETALSILVER RM_KMETALGOLD RM_KSIGNATURE RM_KWAX RM_KPREMIUM RM_HOLO],
55
+ GShortPanelManagement: %w[AUTO CUSTOM OFF],
56
+ GSmoothing: %w[STDSMOOTH ADVSMOOTH NOSMOOTH],
57
+ IGStrictPageSetup: %w[ON OFF],
58
+ FBlackManagement: %w[NOBLACKPOINT ALLBLACKPOINT TEXTINBLACK],
59
+ BBlackManagement: %w[NOBLACKPOINT ALLBLACKPOINT TEXTINBLACK],
60
+ FColorBrightness: (1..20).to_a.map! { |i| "VAL#{i}" },
61
+ BColorBrightness: (1..20).to_a.map! { |i| "VAL#{i}" },
62
+ FColorContrast: (1..20).to_a.map! { |i| "VAL#{i}" },
63
+ BColorContrast: (1..20).to_a.map! { |i| "VAL#{i}" },
64
+ FHalftoning: %w[THRESHOLD FLOYD DITHERING CLUSTERED_DITHERING],
65
+ BHalftoning: %w[THRESHOLD FLOYD DITHERING CLUSTERED_DITHERING],
66
+ FMonochromeContrast: (1..20).to_a.map! { |i| "VAL#{i}" },
67
+ BMonochromeContrast: (1..20).to_a.map! { |i| "VAL#{i}" },
68
+ FOverlayContrast: (1..20).to_a.map! { |i| "VAL#{i}" },
69
+ BOverlayContrast: (1..20).to_a.map! { |i| "VAL#{i}" },
70
+ FOverlayManagement: %w[NOVARNISH FULLVARNISH BMPVARNISH],
71
+ BOverlayManagement: %w[NOVARNISH FULLVARNISH BMPVARNISH],
72
+ FPageRotate180: %w[ON OFF],
73
+ BPageRotate180: %w[ON OFF],
74
+ GMagCoercivity: %w[OFF LOCO HICO],
75
+ GMagT1Encoding: %w[ISO1 ISO2 ISO3 SIPASS C2 JIS2 C4 NONE],
76
+ GMagT2Encoding: %w[ISO1 ISO2 ISO3 SIPASS C2 JIS2 C4 NONE],
77
+ GMagT3Encoding: %w[ISO1 ISO2 ISO3 SIPASS C2 JIS2 C4 NONE],
78
+ Track1Data: String,
79
+ Track2Data: String,
80
+ Track3Data: String,
81
+ Resolution: %w[DPI300 DPI600300 DPI1200300],
82
+ IShortPanelShift: /^[0-9]+$/,
83
+ Passthrough: String,
84
+ RawData: String,
85
+ }
86
+
87
+ # Checks if settings supplied are valid
88
+ #
89
+ # @param settings [String, Array] setting and value,
90
+ # as "setting=value;setting2=value2" or ["setting=value","setting2=value2"]
91
+ # @param key_only [true, false] used for checking if only setting without value. Set to true for setting only.
92
+ # @return [true, false] true if valid settings, false if not
93
+ def valid_settings?(settings, key_only = false)
94
+ settings = settings.split(';') if settings.include?(';')
95
+ settings = [settings] unless settings.is_a?(Array)
96
+
97
+ settings.each do |pair|
98
+ if key_only
99
+ setting = pair
100
+ else
101
+ return false unless pair.include?('=')
102
+ setting, value = pair.split('=')
103
+ end
104
+
105
+ return false unless SETTINGS.has_key?(setting.to_sym)
106
+
107
+ unless key_only
108
+ return false if !value
109
+ return false if value.is_a?(String) && value.empty?
110
+ return false if SETTINGS[setting.to_sym].is_a?(Array) && !SETTINGS[setting.to_sym].include?(value)
111
+ return false if SETTINGS[setting.to_sym].is_a?(Class) && !value.is_a?(SETTINGS[setting.to_sym])
112
+ return false if SETTINGS[setting.to_sym].is_a?(Regexp) && value.is_a?(String) && value !~ SETTINGS[setting.to_sym]
113
+ end
114
+
115
+ return true
116
+ end
117
+ end
118
+
119
+ # Basic checking for valid base64 string, as used in the SDK
120
+ #
121
+ # @param string [String] the base64 encoded data
122
+ # @return [true, false] true if valid base64 string, false if not
123
+ def valid_base64?(string)
124
+ return false unless string.is_a?(String)
125
+ return false unless string.start_with?('base64:')
126
+
127
+ return true
128
+ end
129
+
130
+ # Checks if there is an active session
131
+ # @return [true, false] true if exist, false if not
132
+ def active_session?
133
+ return false unless self.active_session
134
+ return false if self.active_session == nil
135
+ return false unless self.active_session.is_a?(String)
136
+ return false if self.active_session.empty?
137
+
138
+ return true
139
+ end
140
+
141
+ # Sanitizes parameters so they're not anything other than a String
142
+ #
143
+ # @param param [Any type] parameters to be sanitized
144
+ # @return [Hash, Array, String] Hash and Array get sanitized and returned as Hash and Array,
145
+ # everything else becomes a String
146
+ def sanitize_parameters(param)
147
+ return param.map { |p| String(p) } if param.is_a?(Array)
148
+ return param.map { |k, v| [String(k), String(v)] }.to_h if param.is_a?(Hash)
149
+ return String(param)
150
+ end
151
+ end
152
+ end
153
+ end