PEM 이란?
PEM (Privacy Enhanced Mail)은 Base64 로 인코딩한 텍스트 형식의 파일입니다.
Binary 형식의 파일을 전송할 때 손상될 수 있으므로 TEXT 로 변환하며 소스 파일은 모든 바이너리가 가능하지만 주로 인증서나 개인키가 됩니다.
2048 비트의 RSA 키를 생성합니다.
ssh-keygen -t rsa -b 2048 -m pem
cd ~/.ssh
#authorized_keys 파일이 없는 경우 생성
touch authorized_keys
ssh config로 ssh 접속 간편하게 하기
~/.ssh/config
의 설정을 통해 간편하게 접속이 가능 합니다.
Host svr_test
HostName 192.168.1.1
User ubuntu
PreferrAuthentications publickey
IdentityFfile ~/.ssh/my_ssh_key.pem
Continue reading
ssh 접속으로 vnc 모드를 활성화할 필요가 있습니다.
모든 유저를 대상
sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart \
-activate -configure -access -on \
-configure -allowAccessFor -allUsers \
-configure -restart -agent -privs -all
Continue reading
설치하기
터미널에 아래와 같이 입력후 설치를 합니다.
python -m pip install mss
설치된 모듈이 정상적인지 확인합니다.
이미지 처리를 위해서 이미지 처리 모듈을 설치 합니다.
python -m pip install Pillow
스크린샷 만들기
import mss
with mss.mss() as mss_instance:
monitor_1 = mss_instance.monitors[1]capture
screenshot = mss_instance.grab(monitor_1)
스크린샷 보기
from PIL import Image
import mss
with mss.mss() as mss_instance:
monitor_1 = mss_instance.monitors[1]
screenshot = mss_instance.grab(monitor_1)
img = Image.frombytes("RGB", screenshot.size, screenshot.bgra, raw", "BGRX") # Convert to PIL.Image
img.show()
저장하기
import mss
output_filename = 'screenshot.png'
with mss.mss() as mss_instance:
mss_instance.shot(output=output_filename)
File Object 로 저장
import io
from PIL import Image
import mss
bytes_io = io.BytesIO()
with mss.mss() as mss_instance:
monitor_1 = mss_instance.monitors[1]
screenshot = mss_instance.grab(monitor_1)
img = Image.frombytes("RGB", screenshot.size, screenshot.bgra, "raw", "BGRX")
img.save(bytes_io, "PNG")
Continue reading
python boto3 라이브러리로 aws 관련 기능들이 필요하여 가장 중요한 기능들을 정리해 보았습니다.
많은 기능들 중에 아마 upload
, copy
, invalidation
이 가장 많을텐데요.
구글링을 하여 제 입맛에 맞도록 수정하여 정리 하였습니다.
Copy folder
동일 버킷, 혹은 다른 버킷으로 파일 및 폴더를 복사 하는 예제입니다.
s3://aws_bucket/folderA/folderB/000
의 폴더를 folderA/folderB/1111
로 복사를 한다면,
아래의 예제처럼 작성 할 수 있습니다.
import boto3
s3 = boto3.resource('s3')
src_info = "folderA/folderB/0000"
dst_info = "folderA/folderB/1111"
s3_bucket = s3.Bucket('aws_bucket')
for obj in s3_bucket.objects.filter(Prefix=src_info):
old_source = {'Bucket': 'aws_bucket', 'Key': obj.key}
new_key = obj.key.replace(src_info, dst_info, 1)
print(f"Copy {obj.key} -> {new_key}")
new_obj = s3_bucket.Object(new_key)
new_obj.copy(old_source)
Upload folder
boto3 라이브러리에서 폴더를 업로드하는 기능은 지원하지 않아 새로 구현이 필요합니다.
하위 폴더의 재귀적인 호출은 하지 않고 1뎁스 깊이만 폴더 업로드를 지원하는 예제입니다.
import boto3
import os
def upload_dir(profile_name, local_directory, bucket, destination):
if(False == os.path.isdir(local_directory)):
return False
session = boto3.Session(profile_name=profile_name)
s3_client = session.client('s3')
for root, dirs, files in os.walk(local_directory):
for filename in files:
local_path = os.path.join(root, filename)
relative_path = os.path.relpath(local_path, local_directory)
s3_path = f"{destination}/{filename}"
try:
print(f"Uploading {s3_path}")
s3_client.upload_file(local_path, bucket, s3_path, ExtraArgs={
'ACL': 'public-read'})
except ClientError as e:
print(e)
return False
return True
Upload File
가장 많이 사용되는 파일 업로드 기능입니다.
import boto3
def upload_file(profile_name, file_name, bucket, object_name=None):
if object_name is None:
object_name = file_name
session = boto3.Session(profile_name=profile_name)
s3_client = session.client('s3')
try:
print(f"Uploading {object_name}")
response = s3_client.upload_file(
file_name, bucket, object_name, ExtraArgs={'ACL': 'public-read'})
except ClientError as e:
print(e)
return False
return True
Cloudfront Invalidation
DistributionId
는 미리 생성이 필요합니다.
import boto3
def wait_invalidation(dist_id, files):
client = boto3.client('cloudfront')
response = client.create_invalidation(DistributionId=dist_id,
InvalidationBatch={
'Paths': {
'Quantity': len(files),
'Items': ['/{}'.format(f) for f in files]
},
'CallerReference': 'my-references-{}'.format(datetime.datetime.now())})
invalidation_id = response['Invalidation']['Id']
waiter = client.get_waiter('invalidation_completed')
waiter.wait(DistributionId=dist_id,
Id=invalidation_id,
WaiterConfig={
'Delay': 300,
'MaxAttempts': 30
})
return
Continue reading
가끔 vector의 내용을 콤마
로 구분된 출력을 하고 싶을 때가 종종 발생한다.
std::vector to std::string
#include <vector>
#include <string>
#include <algorithm>
#include <sstream>
#include <iterator>
#include <iostream>
int main()
{
std::vector<int> vec;
vec.push_back(1);
vec.push_back(4);
vec.push_back(7);
vec.push_back(4);
vec.push_back(9);
vec.push_back(7);
std::ostringstream oss;
if (!vec.empty())
{
std::copy(vec.begin(), vec.end()-1,
std::ostream_iterator<int>(oss, ","));
oss << vec.back();
}
std::cout << oss.str() << std::endl;
}
std::vector to std::wstring
#include <vector>
#include <string>
#include <algorithm>
#include <sstream>
#include <iterator>
#include <iostream>
int main()
{
std::vector<int> vec;
vec.push_back(1);
vec.push_back(4);
vec.push_back(7);
vec.push_back(4);
vec.push_back(9);
vec.push_back(7);
std::wostringstream oss;
if (!vec.empty())
{
// Convert all but the last element to avoid a trailing ","
std::copy(vec.begin(), vec.end()-1,
std::ostream_iterator<int, wchar_t, std::char_traits<wchar_t> >(oss, L","));
// Now add the last element with no delimiter
oss << vec.back();
}
std::wcout << oss.str() << std::endl;
}
http://cpp.sh/45sy32
Continue reading
스레드풀 소스 코드
#include <chrono>
#include <condition_variable>
#include <cstdio>
#include <functional>
#include <future>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>
class ThreadPool
{
enum class ThreadState
{
NONE = -1,
TERMINATE = 0,
WAIT_PAUSED = 1,
PAUSED = 2,
SLEEPING = 3,
BUSY = 4,
AWAITING = 5,
};
using AsyncQueue = std::queue<std::function<void()>>;
public:
ThreadPool();
virtual ~ThreadPool()
{
if (m_state != ThreadState::TERMINATE)
{
Stop();
}
}
void Initialize(int init_thd)
{
m_workers.reserve(init_thd);
m_state = ThreadState::BUSY;
for (auto i = 0; i < init_thd; ++i)
{
m_workers.emplace_back([this]() { this->WorkerUpdate(); });
}
}
void Stop()
{
m_state = ThreadState::TERMINATE;
m_cond.notify_all();
for (auto &w : m_workers)
{
w.join();
}
}
// 모든 워커 스레드를 일시정시 시킨다.
void PauseWorker()
{
m_state = ThreadState::PAUSED;
m_cond.notify_all();
}
// 모든 워커 스레드를 재가동 한다.
void ResumeWorker()
{
m_state = ThreadState::BUSY;
}
void WorkerUpdate()
{
while (m_state != ThreadState::TERMINATE)
{
if (m_state == ThreadState::PAUSED)
{
while (m_state == ThreadState::PAUSED)
{
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
}
std::unique_lock<std::mutex> lock(m_job_lock);
m_cond.wait(lock, [this]() {return !this->m_jobs.empty() || m_state == ThreadState::TERMINATE || m_state == ThreadState::PAUSED; });
if (m_state == ThreadState::PAUSED)
continue;
if (m_state == ThreadState::TERMINATE)
break;
auto job = std::move(m_jobs.front());
m_jobs.pop();
lock.unlock();
std::chrono::system_clock::time_point begin_time = std::chrono::system_clock::now();
job();
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - begin_time).count();
}
}
ThreadState GetState() { return m_state; }
template< class F, class ... Args>
std::future<std::invoke_result_t<F, Args...>> InsertToThread(F f, Args... args);
private:
std::atomic<ThreadState> m_state = ThreadState::NONE;
std::condition_variable m_cond;
std::vector<std::thread> m_workers;
AsyncQueue m_jobs;
std::mutex m_job_lock;
};
template< class F, class ... Args>
std::future<std::invoke_result_t<F, Args...>>
ThreadPool::InsertToThread(F f, Args... args)
{
if (m_state == ThreadState::TERMINATE)
{
throw std::runtime_error("ThreadPool was terminated.");
}
using return_type = std::invoke_result_t<F, Args...>;
auto job = std::make_shared<std::packaged_task<return_type()>>(std::bind(f, args...));
std::future<return_type> job_result_future = job->get_future();
{
std::lock_guard<std::mutex> lock(m_job_lock);
m_jobs.push([job]() { (*job)(); });
}
m_cond.notify_one();
return job_result_future;
}
// 사용 예시
int work(int t, int id) {
printf("%d start \n", id);
std::this_thread::sleep_for(std::chrono::seconds(t));
printf("%d end after %ds\n", id, t);
return t + id;
}
int main() {
ThreadPool pool(3);
pool.Initialize(3);
std::vector<std::future<int>> futures;
for (int i = 0; i < 10; i++) {
futures.InsertToThread(pool.EnqueueJob(work, i % 3 + 1, i));
}
for (auto& f : futures) {
printf("result : %d \n", f.get());
}
}
Continue reading
C++ 에서 간단하게 문자열 파싱하기
#include <iostream>
#include <string>
#include <sstream>
int main()
{
std::wstring text;
std::wstring data = L"000;123;333";
std::wistringstream token_stream(data.c_str());
while (std::getline(token_stream, text, L';'))
{
if (!text.empty())
{
std::wcout << text << std::endl;
}
}
}
문자열로 파싱하기
#include <iostream>
#include <string>
int main()
{
std::string s = "scott>=tiger>=mushroom";
std::string delimiter = ">=";
size_t last = 0;
size_t next = 0;
while ((next = s.find(delimiter, last)) != std::string::npos)
{
std::cout << s.substr(last, next-last) << std::endl;
last = next + delimiter.length();
}
std::cout << s.substr(last) << std::endl;
}
Continue reading
Synology Jekyll Docker
github.io 도 있지만 개인 보유하고 있는 Nas 를 이용해서 개인 블러그를 운영을 위해서 작성합니다.
하루 종일 이것 저것 삽질하면서 잘 안되 포기 할까도 생각했지만 오기 발동하여 결국 성공!!
Jekyll Docker 의 문서에 아주 잘 나와 있는데 Synology 에서 적용 한다고 삽질을….
https://github.com/envygeeks/jekyll-docker/blob/master/README.md
간략히 내용을 정리 해보면, jekyll_home 생성 후 bundle 파일을 저장하기 위한 커스텀 폴더 생성 jekyll bundle update
를 실행하여 필요한 bundle 파일을 업데이트 후 -w
옵션을 이용한 변경 감지를 통해서 자동 정적 페이지 생성을 한다. 입니다.
Docker
저장소에서 jekyll
검색한후 jekyll/jekyll
이미지를 다운로드 합니다.
jekyll
의 원본이 위치한 경로의 접근 권한을 everyone
으로 읽기쓰기가 가능 하도록 먼저 설정합니다. 실행권한을 최고 권한으로 실행했지만 결국은 권한이 없다고 에러가.. 꼭! everyone
으로 읽기 쓰기를 설정하세요.
저는 jekyll_home
공유 폴더를 생성 후 이미 theme 를 생성한 폴더와 파일을 준비 하였습니다. 이 부분은 여기서 다루지 않을 예정입니다.
Dependencies
jekyll Docker Gemfile
의 리스트에서 의존성 파일을 설치 하게 됩니다.
Updatding & Caching
jekyll_home/vendor/bundle
폴더는 생성해주세요. Gemfile
을 제공한다면, 아래와 같이 실행 합니다.
docker run --rm \
--volume="/volume1/jekyll_home:/srv/jekyll" \
--volume="/volume1/jekyll_home/vendor/bundle:/usr/local/bundle" \
-it jekyll/jekyll:3.8.6 \
bundle update
필요한 파일을 자동으로 다운로드 하여, vendor/bundle 폴더에 필요한 파일을 자동으로 다운을 시작합니다. 이부분을 저는 잘 이해를 못해서 하루 삽질했네요.
/jekyll_home/vendor/bundle
폴더에는 아래와 같이 폴더와 파일이 생성된것 을 확인 할 수 있습니다.
Build(생성하기)
이제 정적 페이지를 생성 하기 위해서는 bundle 에 캐싱한 내용을 이용하여 아래의 명령을 실행하면, jekyll_home/_site
폴더가 생성되고 정적 파일들이 생성되는 것을 확인 할 수 있습니다.
최신 버전의 jekyll 에서는 bundle install 시 번들 경로가 문제가 될수 있습니다.
docker run --rm \
--volume="/volume1/jekyll_home:/srv/jekyll" \
--volume="/volume1/jekyll_home/vendor/bundle:/usr/local/bundle" \
-it jekyll/jekyll:3.8.6 \
jekyll build
_post
폴더의 변경된 내용을 자동으로 감지후 페이지 생성을 위해서는 synology
에서 Docker
이미지를 실행하여 자동으로 생성 하도록 하면 됩니다.
Synology Docker 를 이용하여 자동 변경 감지 후 자동 생성하자
이미지를 클릭 후 실행 버튼을 클릭하여 컨테이너를 생성 하도록 합니다.
컨테이너 이름은 적당한 이름을 작성하고 고급 설정을 클릭하여 , 캐싱한 bundle 경로와 jekyll 문서가 있는 루트 경로를 볼륨으로 추가합니다.
볼륨 추가
환경 설정 탭에서 실행명령 란에 jekyll build -w
을 입력후 적용 버튼 누릅니다.
모든게 완료 되었다면 jekyll_home/_site
폴더가 생성된 후 정적페이지를 위한 파일들이 자동 생성 됨을 확인 할 수 있습니다.
Continue reading